diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix
index 695c0b6620f..36c915f755f 100644
--- a/nixos/modules/programs/shadow.nix
+++ b/nixos/modules/programs/shadow.nix
@@ -79,22 +79,22 @@ in
];
security.pam.services =
- [ { name = "chsh"; rootOK = true; }
- { name = "chfn"; rootOK = true; }
- { name = "su"; rootOK = true; forwardXAuth = true; }
- { name = "passwd"; }
+ { chsh = { rootOK = true; };
+ chfn = { rootOK = true; };
+ su = { rootOK = true; forwardXAuth = true; };
+ passwd = {};
# Note: useradd, groupadd etc. aren't setuid root, so it
# doesn't really matter what the PAM config says as long as it
# lets root in.
- { name = "useradd"; rootOK = true; }
- { name = "usermod"; rootOK = true; }
- { name = "userdel"; rootOK = true; }
- { name = "groupadd"; rootOK = true; }
- { name = "groupmod"; rootOK = true; }
- { name = "groupmems"; rootOK = true; }
- { name = "groupdel"; rootOK = true; }
- { name = "login"; startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; }
- ];
+ useradd = { rootOK = true; };
+ usermod = { rootOK = true; };
+ userdel = { rootOK = true; };
+ groupadd = { rootOK = true; };
+ groupmod = { rootOK = true; };
+ groupmems = { rootOK = true; };
+ groupdel = { rootOK = true; };
+ login = { startSession = true; allowNullPassword = true; showMotd = true; updateWtmp = true; };
+ };
security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ];
diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
index 3ef01ea2c17..d078ed1e1bb 100644
--- a/nixos/modules/security/pam.nix
+++ b/nixos/modules/security/pam.nix
@@ -7,77 +7,138 @@ with pkgs.lib;
let
- inherit (pkgs) pam_krb5 pam_ccreds;
+ pamOpts = args: {
- pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
+ options = {
- otherService = pkgs.writeText "other.pam"
- ''
- auth required pam_warn.so
- auth required pam_deny.so
- account required pam_warn.so
- account required pam_deny.so
- password required pam_warn.so
- password required pam_deny.so
- session required pam_warn.so
- session required pam_deny.so
- '';
+ name = mkOption {
+ example = "sshd";
+ type = types.uniq types.string;
+ description = "Name of the PAM service.";
+ };
- # Create a limits.conf(5) file.
- makeLimitsConf = limits:
- pkgs.writeText "limits.conf"
- (concatStringsSep "\n"
- (map ({ domain, type, item, value }:
- concatStringsSep " " [ domain type item value ])
- limits));
+ rootOK = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ If set, root doesn't need to authenticate (e.g. for the
+ useradd service).
+ '';
+ };
- motd = pkgs.writeText "motd" config.users.motd;
+ usbAuth = mkOption {
+ default = config.security.pam.usb.enable;
+ type = types.bool;
+ description = ''
+ If set, users listed in
+ /etc/pamusb.conf are able to log in
+ with the associated USB key.
+ '';
+ };
- makePAMService =
- { name
- , # If set, root doesn't need to authenticate (e.g. for the "chsh"
- # service).
- rootOK ? false
- , # If set, user listed in /etc/pamusb.conf are able to log in with
- # the associated usb key.
- usbAuth ? config.security.pam.usb.enable
- , # If set, OTPW system will be used (if ~/.otpw exists)
- otpwAuth ? config.security.pam.enableOTPW
- , # If set, the calling user's SSH agent is used to authenticate
- # against the keys in the calling user's ~/.ssh/authorized_keys.
- # This is useful for "sudo" on password-less remote systems.
- sshAgentAuth ? false
- , # If set, the service will register a new session with systemd's
- # login manager. If the service is running locally, this will
- # give the user ownership of audio devices etc.
- startSession ? false
- , # Set the login uid of the process (/proc/self/loginuid) for
- # auditing purposes. The login uid is only set by "entry
- # points" like login and sshd, not by commands like sudo.
- setLoginUid ? startSession
- , # Whether to forward XAuth keys between users. Mostly useful
- # for "su".
- forwardXAuth ? false
- , # Whether to allow logging into accounts that have no password
- # set (i.e., have an empty password field in /etc/passwd or
- # /etc/group). This does not enable logging into disabled
- # accounts (i.e., that have the password field set to `!').
- # Note that regardless of what the pam_unix documentation says,
- # accounts with hashed empty passwords are always allowed to log
- # in.
- allowNullPassword ? false
- , # The limits, as per limits.conf(5).
- limits ? config.security.pam.loginLimits
- , # Whether to show the message of the day.
- showMotd ? false
- , # Whether to update /var/log/wtmp.
- updateWtmp ? false
- }:
+ otpwAuth = mkOption {
+ default = config.security.pam.enableOTPW;
+ type = types.bool;
+ description = ''
+ If set, the OTPW system will be used (if
+ ~/.otpw exists).
+ '';
+ };
- { source = pkgs.writeText "${name}.pam"
- # !!! TODO: move the LDAP stuff to the LDAP module, and the
- # Samba stuff to the Samba module. This requires that the PAM
- # module provides the right hooks.
+ sshAgentAuth = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ If set, the calling user's SSH agent is used to authenticate
+ against the keys in the calling user's
+ ~/.ssh/authorized_keys. This is useful
+ for sudo on password-less remote systems.
+ '';
+ };
+
+ startSession = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ If set, the service will register a new session with
+ systemd's login manager. For local sessions, this will give
+ the user access to audio devices, CD-ROM drives. In the
+ default PolicyKit configuration, it also allows the user to
+ reboot the system.
+ '';
+ };
+
+ setLoginUid = mkOption {
+ type = types.bool;
+ description = ''
+ Set the login uid of the process
+ (/proc/self/loginuid) for auditing
+ purposes. The login uid is only set by ‘entry points’ like
+ login and sshd, not by
+ commands like sudo.
+ '';
+ };
+
+ forwardXAuth = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether X authentication keys should be passed from the
+ calling user to the target user (e.g. for
+ su)
+ '';
+ };
+
+ allowNullPassword = mkOption {
+ default = false;
+ type = types.bool;
+ description = ''
+ Whether to allow logging into accounts that have no password
+ set (i.e., have an empty password field in
+ /etc/passwd or
+ /etc/group). This does not enable
+ logging into disabled accounts (i.e., that have the password
+ field set to !). Note that regardless of
+ what the pam_unix documentation says, accounts with hashed
+ empty passwords are always allowed to log in.
+ '';
+ };
+
+ limits = mkOption {
+ description = ''
+ Attribute set describing resource limits. Defaults to the
+ value of .
+ '';
+ };
+
+ showMotd = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Whether to show the message of the day.";
+ };
+
+ updateWtmp = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Whether to update /var/log/wtmp.";
+ };
+
+ text = mkOption {
+ type = types.nullOr types.string;
+ description = "Contents of the PAM service file.";
+ };
+
+ };
+
+ config = let cfg = args.config; in {
+ name = mkDefault args.name;
+ setLoginUid = mkDefault cfg.startSession;
+ limits = mkDefault config.security.pam.loginLimits;
+
+ # !!! TODO: move the LDAP stuff to the LDAP module, and the
+ # Samba stuff to the Samba module. This requires that the PAM
+ # module provides the right hooks.
+ text = mkDefault
''
# Account management.
account sufficient pam_unix.so
@@ -87,14 +148,14 @@ let
"account sufficient ${pam_krb5}/lib/security/pam_krb5.so"}
# Authentication management.
- ${optionalString rootOK
+ ${optionalString cfg.rootOK
"auth sufficient pam_rootok.so"}
- ${optionalString (config.security.pam.enableSSHAgentAuth && sshAgentAuth)
+ ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth)
"auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"}
- ${optionalString usbAuth
+ ${optionalString cfg.usbAuth
"auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"}
- auth sufficient pam_unix.so ${optionalString allowNullPassword "nullok"} likeauth
- ${optionalString otpwAuth
+ auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth
+ ${optionalString cfg.otpwAuth
"auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"}
${optionalString config.users.ldap.enable
"auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"}
@@ -116,26 +177,47 @@ let
# Session management.
session required pam_unix.so
- ${optionalString updateWtmp
+ ${optionalString cfg.updateWtmp
"session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"}
${optionalString config.users.ldap.enable
"session optional ${pam_ldap}/lib/security/pam_ldap.so"}
${optionalString config.krb5.enable
"session optional ${pam_krb5}/lib/security/pam_krb5.so"}
- ${optionalString otpwAuth
+ ${optionalString cfg.otpwAuth
"session optional ${pkgs.otpw}/lib/security/pam_otpw.so"}
- ${optionalString startSession
+ ${optionalString cfg.startSession
"session optional ${pkgs.systemd}/lib/security/pam_systemd.so"}
- ${optionalString setLoginUid
+ ${optionalString cfg.setLoginUid
"session required pam_loginuid.so"}
- ${optionalString forwardXAuth
+ ${optionalString cfg.forwardXAuth
"session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99"}
- ${optionalString (limits != [])
+ ${optionalString (cfg.limits != [])
"session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf limits}"}
- ${optionalString (showMotd && config.users.motd != null)
+ ${optionalString (cfg.showMotd && config.users.motd != null)
"session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"}
'';
- target = "pam.d/${name}";
+ };
+
+ };
+
+
+ inherit (pkgs) pam_krb5 pam_ccreds;
+
+ pam_ldap = if config.users.ldap.daemon.enable then pkgs.nss_pam_ldapd else pkgs.pam_ldap;
+
+ # Create a limits.conf(5) file.
+ makeLimitsConf = limits:
+ pkgs.writeText "limits.conf"
+ (concatStringsSep "\n"
+ (map ({ domain, type, item, value }:
+ concatStringsSep " " [ domain type item value ])
+ limits));
+
+ motd = pkgs.writeText "motd" config.users.motd;
+
+ makePAMService = pamService:
+ { source = pkgs.writeText "${pamService.name}.pam" pamService.text;
+ target = "pam.d/${pamService.name}";
};
in
@@ -173,44 +255,15 @@ in
security.pam.services = mkOption {
default = [];
- example = [
- { name = "chsh"; rootOK = true; }
- { name = "login"; startSession = true; allowNullPassword = true;
- limits = [
- { domain = "ftp";
- type = "hard";
- item = "nproc";
- value = "0";
- }
- ];
- }
- ];
-
+ type = types.loaOf types.optionSet;
+ options = [ pamOpts ];
description =
''
This option defines the PAM services. A service typically
corresponds to a program that uses PAM,
e.g. login or passwd.
- Each element of this list is an attribute set describing a
- service. The attribute name specifies
- the name of the service. The attribute
- rootOK specifies whether the root user is
- allowed to use this service without authentication. The
- attribute startSession specifies whether
- systemd's PAM connector module should be used to start a new
- session; for local sessions, this will give the user
- ownership of devices such as audio and CD-ROM drives. The
- attribute forwardXAuth specifies whether
- X authentication keys should be passed from the calling user
- to the target user (e.g. for su).
-
- The attribute limits defines resource limits
- that should apply to users or groups for the service. Each item in
- the list should be an attribute set with a
- domain, type,
- item, and value attribute.
- The syntax and semantics of these attributes must be that described
- in the limits.conf(5) man page.
+ Each attribute of this set defines a PAM service, with the attribute name
+ defining the name of the service.
'';
};
@@ -228,7 +281,7 @@ in
security.pam.enableOTPW = mkOption {
default = false;
description = ''
- Enable the OTPW (one-time password) PAM module
+ Enable the OTPW (one-time password) PAM module.
'';
};
@@ -254,11 +307,7 @@ in
++ optionals config.security.pam.enableOTPW [ pkgs.otpw ];
environment.etc =
- map makePAMService config.security.pam.services
- ++ singleton
- { source = otherService;
- target = "pam.d/other";
- };
+ mapAttrsToList (n: v: makePAMService v) config.security.pam.services;
security.setuidOwners = [ {
program = "unix_chkpwd";
@@ -268,18 +317,27 @@ in
} ];
security.pam.services =
- # Most of these should be moved to specific modules.
- [ { name = "cups"; }
- { name = "ejabberd"; }
- { name = "ftp"; }
- { name = "i3lock"; }
- { name = "lshd"; }
- { name = "samba"; }
- { name = "screen"; }
- { name = "vlock"; }
- { name = "xlock"; }
- { name = "xscreensaver"; }
- ];
+ { other.text =
+ ''
+ auth required pam_warn.so
+ auth required pam_deny.so
+ account required pam_warn.so
+ account required pam_deny.so
+ password required pam_warn.so
+ password required pam_deny.so
+ session required pam_warn.so
+ session required pam_deny.so
+ '';
+
+ # Most of these should be moved to specific modules.
+ cups = {};
+ ftp = {};
+ i3lock = {};
+ screen = {};
+ vlock = {};
+ xlock = {};
+ xscreensaver = {};
+ };
};
diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix
index 1c2a6a05f26..2bd3069ddb1 100644
--- a/nixos/modules/security/pam_usb.nix
+++ b/nixos/modules/security/pam_usb.nix
@@ -8,7 +8,7 @@ let
cfg = config.security.pam.usb;
- anyUsbAuth = any (attrByPath ["usbAuth"] false) config.security.pam.services;
+ anyUsbAuth = any (attrByPath ["usbAuth"] false) (attrValues config.security.pam.services);
in
@@ -19,8 +19,8 @@ in
enable = mkOption {
default = false;
description = ''
- Enable USB login for all login system unless the service disabled
- it. For more information, visit .
'';
};
diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix
index b9b32496a36..8b04f4043bc 100644
--- a/nixos/modules/security/polkit.nix
+++ b/nixos/modules/security/polkit.nix
@@ -94,7 +94,7 @@ in
services.dbus.packages = [ pkgs.polkit ];
- security.pam.services = [ { name = "polkit-1"; } ];
+ security.pam.services.polkit-1 = {};
security.setuidPrograms = [ "pkexec" ];
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index cd548f4a4fe..77251780198 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -74,7 +74,7 @@ in
environment.systemPackages = [ sudo ];
- security.pam.services = [ { name = "sudo"; sshAgentAuth = true; } ];
+ security.pam.services.sudo = { sshAgentAuth = true; };
environment.etc = singleton
{ source = pkgs.writeText "sudoers-in" cfg.configFile;
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 5f8e8e1ade3..92682d644f4 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -124,7 +124,7 @@ in
config = mkIf config.services.dovecot2.enable {
- security.pam.services = [ { name = "dovecot2"; } ];
+ security.pam.services.dovecot2 = {};
users.extraUsers = [
{ name = cfg.user;
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 70a14487ea5..e18d9d7b67b 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -198,6 +198,7 @@ in
}
(mkIf config.services.samba.enable {
+
users.extraUsers.smbguest = {
description = "Samba service user";
group = group;
@@ -228,6 +229,8 @@ in
};
};
+ security.pam.services.sambda = {};
+
})
];
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 6d233e543e2..05e0aba7d70 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -130,6 +130,8 @@ in
'';
};
+ security.pam.services.ejabberd = {};
+
};
}
diff --git a/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix
index d32fabbde24..04ef76f1e4d 100644
--- a/nixos/modules/services/networking/ssh/lshd.nix
+++ b/nixos/modules/services/networking/ssh/lshd.nix
@@ -170,6 +170,8 @@ in
'';
};
+ security.pam.services.lshd = {};
+
};
}
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index c9a4a9087e5..1c3dc9d90b1 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -219,5 +219,7 @@ in
# Allow CUPS to receive IPP printer announcements via UDP.
networking.firewall.allowedUDPPorts = [ 631 ];
+ security.pam.services.cups = {};
+
};
}
diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix
index 88bec2cb2f3..8c96252668e 100644
--- a/nixos/modules/services/scheduling/atd.nix
+++ b/nixos/modules/services/scheduling/atd.nix
@@ -49,7 +49,7 @@ in
environment.systemPackages = [ at ];
- security.pam.services = [ { name = "atd"; } ];
+ security.pam.services.atd = {};
users.extraUsers = singleton
{ name = "atd";
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index c76acfbcd4e..d1eb1799bc8 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -162,7 +162,7 @@ in
services.udisks2.enable = wantsUdisks2;
services.upower.enable = config.powerManagement.enable;
- security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
+ security.pam.services.kde = { allowNullPassword = true; };
};
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index 229ab12c6e1..2e84adcb4ce 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -138,7 +138,7 @@ in
logsXsession = true;
};
- security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
+ security.pam.services.kde = { allowNullPassword = true; startSession = true; };
users.extraUsers = singleton
{ name = "kdm";
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index c2b90d239ea..266f16e18e3 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -102,10 +102,8 @@ in
services.dbus.enable = true;
services.dbus.packages = [ lightdm ];
- security.pam.services = [
- { name = "lightdm"; allowNullPassword = true; startSession = true; }
- { name = "lightdm-greeter"; allowNullPassword = true; startSession = true; }
- ];
+ security.pam.services.lightdm = { allowNullPassword = true; startSession = true; };
+ security.pam.services.lightdm-greeter = { allowNullPassword = true; startSession = true; };
users.extraUsers.lightdm = {
createHome = true;
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index f9b81f8f040..7b2c52ca398 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -104,14 +104,12 @@ in
execCmd = "exec ${pkgs.slim}/bin/slim";
};
- security.pam.services =
- [ # Allow null passwords so that the user can login as root on the
- # installation CD.
- { name = "slim"; allowNullPassword = true; startSession = true; }
+ # Allow null passwords so that the user can login as root on the
+ # installation CD.
+ security.pam.services.slim = { allowNullPassword = true; startSession = true; };
- # Allow slimlock to work.
- { name = "slimlock"; }
- ];
+ # Allow slimlock to work.
+ security.pam.services.slimlock = {};
environment.systemPackages = [ pkgs.slim ];