From 4b864991aa141958fc701e4925527fbf45ff1bf0 Mon Sep 17 00:00:00 2001 From: Majiir Paktu Date: Sat, 28 Jun 2025 19:53:19 -0400 Subject: [PATCH] nixos: replace 'text' with structured PAM rules Several modules define whole PAM service rule stacks by overwriting the default value of the 'text' option. Instead, we disable useDefaultRules for these services and declare a new set of rules using the 'rules' option. This option is considered experimental and hidden from users, but it is supported for use within nixpkgs. --- nixos/modules/security/pam.nix | 34 +- .../modules/services/display-managers/gdm.nix | 304 +++++++++++++++--- .../modules/services/display-managers/ly.nix | 58 +++- .../display-managers/plasma-login-manager.nix | 149 +++++++-- .../services/display-managers/sddm.nix | 197 ++++++++++-- nixos/modules/services/networking/vsftpd.nix | 23 +- nixos/modules/services/wayland/cage.nix | 47 ++- .../services/x11/display-managers/lightdm.nix | 221 +++++++++++-- 8 files changed, 873 insertions(+), 160 deletions(-) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index a9c2d5fe6413..2c6b3419bf2f 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -2548,16 +2548,30 @@ in }; security.pam.services = { - other.text = '' - auth required ${package}/lib/security/pam_warn.so - auth required ${package}/lib/security/pam_deny.so - account required ${package}/lib/security/pam_warn.so - account required ${package}/lib/security/pam_deny.so - password required ${package}/lib/security/pam_warn.so - password required ${package}/lib/security/pam_deny.so - session required ${package}/lib/security/pam_warn.so - session required ${package}/lib/security/pam_deny.so - ''; + other = { + useDefaultRules = false; + rules = + let + rules = utils.pam.autoOrderRules [ + { + name = "warn"; + control = "required"; + modulePath = "${package}/lib/security/pam_warn.so"; + } + { + name = "deny"; + control = "required"; + modulePath = "${package}/lib/security/pam_deny.so"; + } + ]; + in + { + auth = rules; + account = rules; + password = rules; + session = rules; + }; + }; # Most of these should be moved to specific modules. i3lock.enable = lib.mkDefault config.programs.i3lock.enable; diff --git a/nixos/modules/services/display-managers/gdm.nix b/nixos/modules/services/display-managers/gdm.nix index 18998ddeb34f..6de21115eb2a 100644 --- a/nixos/modules/services/display-managers/gdm.nix +++ b/nixos/modules/services/display-managers/gdm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -383,67 +384,280 @@ in # GDM LFS PAM modules, adapted somehow to NixOS security.pam.services = { - gdm-launch-environment.text = '' - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - auth optional ${config.security.pam.package}/lib/security/pam_permit.so + gdm-launch-environment = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - account sufficient ${config.security.pam.package}/lib/security/pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user ingroup gdm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "gdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "ingroup" + "gdm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - gdm-password.text = '' - auth substack login - account include login - password substack login - session include login - ''; + gdm-password = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - gdm-autologin.text = '' - auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= 1000 quiet - ${lib.optionalString (pamLogin.enable && pamLogin.enableGnomeKeyring) '' - auth [success=ok default=1] ${gdm}/lib/security/pam_gdm.so - auth optional ${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so - ''} - auth required ${config.security.pam.package}/lib/security/pam_permit.so + gdm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "gdm-normal-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "gdm"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "[success=ok default=1]"; + modulePath = "${gdm}/lib/security/pam_gdm.so"; + } + { + name = "gnome_keyring"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "optional"; + modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account sufficient ${config.security.pam.package}/lib/security/pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password requisite ${config.security.pam.package}/lib/security/pam_unix.so nullok yescrypt + password = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + settings.yescrypt = true; + } + ]; - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so revoke - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.revoke = true; + } + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; # This would block password prompt when included by gdm-password. # GDM will instead run gdm-fingerprint in parallel. login.fprintAuth = lib.mkIf config.services.fprintd.enable false; - gdm-fingerprint.text = lib.mkIf config.services.fprintd.enable '' - auth required ${config.security.pam.package}/lib/security/pam_shells.so - auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so - auth requisite ${config.security.pam.package}/lib/security/pam_faillock.so preauth - auth required ${pkgs.fprintd}/lib/security/pam_fprintd.so - auth required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - ${lib.optionalString (pamLogin.enable && pamLogin.enableGnomeKeyring) '' - auth [success=ok default=1] ${gdm}/lib/security/pam_gdm.so - auth optional ${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so - ''} + gdm-fingerprint = lib.mkIf config.services.fprintd.enable { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "shells"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_shells.so"; + } + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "faillock"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_faillock.so"; + settings.preauth = true; + } + { + name = "fprintd"; + control = "required"; + modulePath = "${pkgs.fprintd}/lib/security/pam_fprintd.so"; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "gdm"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "[success=ok default=1]"; + modulePath = "${gdm}/lib/security/pam_gdm.so"; + } + { + name = "gnome_keyring"; + enable = pamLogin.enable && pamLogin.enableGnomeKeyring; + control = "optional"; + modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so"; + } + ]; - account include login + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; - password required ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; }; }; diff --git a/nixos/modules/services/display-managers/ly.nix b/nixos/modules/services/display-managers/ly.nix index 8d671ca5242f..a75da6f68078 100644 --- a/nixos/modules/services/display-managers/ly.nix +++ b/nixos/modules/services/display-managers/ly.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -105,17 +106,58 @@ in }; } // optionalAttrs dmcfg.autoLogin.enable { - ly-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_succeed_if.so uid >= 1000 quiet - auth required pam_permit.so + ly-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "pam_nologin.so"; + } + { + name = "ly-normal-user"; + control = "required"; + modulePath = "pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - account include ly + account = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; - password include ly + password = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; - session include ly - ''; + session = utils.pam.autoOrderRules [ + { + name = "ly"; + control = "include"; + modulePath = "ly"; + } + ]; + }; + }; }; environment = { diff --git a/nixos/modules/services/display-managers/plasma-login-manager.nix b/nixos/modules/services/display-managers/plasma-login-manager.nix index 8bfcfc37f4f7..4c98f75b8973 100644 --- a/nixos/modules/services/display-managers/plasma-login-manager.nix +++ b/nixos/modules/services/display-managers/plasma-login-manager.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -83,39 +84,133 @@ in environment.etc."plasmalogin.conf.d/99-user.conf".source = userConfigFile; security.pam.services = { - plasmalogin.text = '' - auth substack login - account include login - password substack login - session include login - ''; + plasmalogin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - plasmalogin-autologin.text = '' - auth requisite pam_nologin.so - auth required pam_permit.so + plasmalogin-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "pam_nologin.so"; + } + { + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - account include plasmalogin - password include plasmalogin - session include plasmalogin - ''; + account = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "plasmalogin"; + control = "include"; + modulePath = "plasmalogin"; + } + ]; + }; + }; - plasmalogin-greeter.text = '' - # Load environment from /etc/environment and ~/.pam_environment - auth required pam_env.so conffile=/etc/pam/environment readenv=0 + plasmalogin-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + # Load environment from /etc/environment and ~/.pam_environment + name = "env"; + control = "required"; + modulePath = "pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + # Always let the greeter start without authentication + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - # Always let the greeter start without authentication - auth required pam_permit.so + account = utils.pam.autoOrderRules [ + { + # No action required for account management + name = "permit"; + control = "required"; + modulePath = "pam_permit.so"; + } + ]; - # No action required for account management - account required pam_permit.so + password = utils.pam.autoOrderRules [ + { + # Can't change password + name = "deny"; + control = "required"; + modulePath = "pam_deny.so"; + } + ]; - # Can't change password - password required pam_deny.so - - # Setup session - session required pam_unix.so - session optional ${config.systemd.package}/lib/security/pam_systemd.so - ''; + session = utils.pam.autoOrderRules [ + { + # Setup session + name = "unix"; + control = "required"; + modulePath = "pam_unix.so"; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + ]; + }; + }; }; # FIXME: use upstream sysusers diff --git a/nixos/modules/services/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix index 25f63007f9ac..5cb750786b00 100644 --- a/nixos/modules/services/display-managers/sddm.nix +++ b/nixos/modules/services/display-managers/sddm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -368,40 +369,184 @@ in }; security.pam.services = { - sddm.text = '' - auth substack login - account include login - password substack login - session include login - ''; + sddm = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - sddm-greeter.text = '' - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - auth optional ${config.security.pam.package}/lib/security/pam_permit.so + sddm-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - account sufficient ${config.security.pam.package}/lib/security/pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = sddm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "sddm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "sddm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - sddm-autologin.text = '' - auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= ${toString cfg.autoLogin.minimumUid} quiet - auth required ${config.security.pam.package}/lib/security/pam_permit.so + sddm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "sddm-autologin-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + (toString cfg.autoLogin.minimumUid) + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account include sddm + account = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; - password include sddm + password = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; - session include sddm - ''; + session = utils.pam.autoOrderRules [ + { + name = "sddm"; + control = "include"; + modulePath = "sddm"; + } + ]; + }; + }; }; users.users.sddm = { diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix index 070f77115829..481ceb74886e 100644 --- a/nixos/modules/services/networking/vsftpd.nix +++ b/nixos/modules/services/networking/vsftpd.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -333,9 +334,23 @@ in }; }; - security.pam.services.vsftpd.text = mkIf (cfg.enableVirtualUsers && cfg.userDbPath != null) '' - auth required ${config.security.pam.package}/lib/security/pam_userdb.so db=${cfg.userDbPath} - account required ${config.security.pam.package}/lib/security/pam_userdb.so db=${cfg.userDbPath} - ''; + security.pam.services.vsftpd = mkIf (cfg.enableVirtualUsers && cfg.userDbPath != null) { + useDefaultRules = false; + rules = + let + rules = utils.pam.autoOrderRules [ + { + name = "userdb"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_userdb.so"; + settings.db = cfg.userDbPath; + } + ]; + in + { + auth = rules; + account = rules; + }; + }; }; } diff --git a/nixos/modules/services/wayland/cage.nix b/nixos/modules/services/wayland/cage.nix index 76731622d50a..006520ea9b63 100644 --- a/nixos/modules/services/wayland/cage.nix +++ b/nixos/modules/services/wayland/cage.nix @@ -2,6 +2,7 @@ config, pkgs, lib, + utils, ... }: @@ -105,13 +106,45 @@ in security.polkit.enable = true; - security.pam.services.cage.text = '' - auth required ${config.security.pam.package}/lib/security/pam_unix.so nullok - account required ${config.security.pam.package}/lib/security/pam_unix.so - session required ${config.security.pam.package}/lib/security/pam_unix.so - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session required ${config.systemd.package}/lib/security/pam_systemd.so - ''; + security.pam.services.cage = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "required"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + ]; + }; + }; hardware.graphics.enable = mkDefault true; diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index b0e757b21f5f..699a9a9a07f3 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -1,6 +1,7 @@ { config, lib, + utils, pkgs, ... }: @@ -279,47 +280,201 @@ in security.polkit.enable = true; - security.pam.services.lightdm.text = '' - auth substack login - account include login - password substack login - session include login - '' - # https://github.com/elementary/switchboard-plug-parental-controls/blob/8.0.1/src/daemon/Server.vala#L325 - # Must specify conffile since pam_time defaults to ${linux-pam}/etc/security/time.conf. - + lib.optionalString config.services.pantheon.parental-controls.enable '' - account required ${config.security.pam.package}/lib/security/pam_time.so conffile=/etc/security/time.conf - ''; + security.pam.services.lightdm = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + account = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + { + name = "time"; + # https://github.com/elementary/switchboard-plug-parental-controls/blob/8.0.1/src/daemon/Server.vala#L325 + enable = config.services.pantheon.parental-controls.enable; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_time.so"; + # Must specify conffile since pam_time defaults to ${linux-pam}/etc/security/time.conf. + settings.conffile = "/etc/security/time.conf"; + } + ]; + password = utils.pam.autoOrderRules [ + { + name = "login"; + control = "substack"; + modulePath = "login"; + } + ]; + session = utils.pam.autoOrderRules [ + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; - security.pam.services.lightdm-greeter.text = '' - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - auth optional ${config.security.pam.package}/lib/security/pam_permit.so + security.pam.services.lightdm-greeter = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - account required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - account sufficient ${config.security.pam.package}/lib/security/pam_unix.so + account = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - password required ${config.security.pam.package}/lib/security/pam_deny.so + password = utils.pam.autoOrderRules [ + { + name = "deny"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_deny.so"; + } + ]; - session required ${config.security.pam.package}/lib/security/pam_succeed_if.so audit quiet_success user = lightdm - session required ${config.security.pam.package}/lib/security/pam_env.so conffile=/etc/pam/environment readenv=0 - session optional ${config.systemd.package}/lib/security/pam_systemd.so - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so force revoke - session optional ${config.security.pam.package}/lib/security/pam_permit.so - ''; + session = utils.pam.autoOrderRules [ + { + name = "lightdm-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.audit = true; + settings.quiet_success = true; + args = lib.mkAfter [ + "user" + "=" + "lightdm" + ]; + } + { + name = "env"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_env.so"; + settings.conffile = "/etc/pam/environment"; + settings.readenv = 0; + } + { + name = "systemd"; + control = "optional"; + modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; + } + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.force = true; + settings.revoke = true; + } + { + name = "permit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; + }; + }; - security.pam.services.lightdm-autologin.text = '' - auth requisite ${config.security.pam.package}/lib/security/pam_nologin.so + security.pam.services.lightdm-autologin = { + useDefaultRules = false; + rules = { + auth = utils.pam.autoOrderRules [ + { + name = "nologin"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so"; + } + { + name = "lightdm-normal-user"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so"; + settings.quiet = true; + args = lib.mkBefore [ + "uid" + ">=" + "1000" + ]; + } + { + name = "permit"; + control = "required"; + modulePath = "${config.security.pam.package}/lib/security/pam_permit.so"; + } + ]; - auth required ${config.security.pam.package}/lib/security/pam_succeed_if.so uid >= 1000 quiet - auth required ${config.security.pam.package}/lib/security/pam_permit.so + account = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "sufficient"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + } + ]; - account sufficient ${config.security.pam.package}/lib/security/pam_unix.so + password = utils.pam.autoOrderRules [ + { + name = "unix"; + control = "requisite"; + modulePath = "${config.security.pam.package}/lib/security/pam_unix.so"; + settings.nullok = true; + settings.yescrypt = true; + } + ]; - password requisite ${config.security.pam.package}/lib/security/pam_unix.so nullok yescrypt - - session optional ${config.security.pam.package}/lib/security/pam_keyinit.so revoke - session include login - ''; + session = utils.pam.autoOrderRules [ + { + name = "keyinit"; + control = "optional"; + modulePath = "${config.security.pam.package}/lib/security/pam_keyinit.so"; + settings.revoke = true; + } + { + name = "login"; + control = "include"; + modulePath = "login"; + } + ]; + }; + }; users.users.lightdm = { home = "/var/lib/lightdm";