at 24.05-pre 8.5 kB view raw
1# Configuration for the pwdutils suite of tools: passwd, useradd, etc. 2{ config, lib, utils, pkgs, ... }: 3with lib; 4let 5 cfg = config.security.loginDefs; 6in 7{ 8 options = with types; { 9 security.loginDefs = { 10 package = mkPackageOptionMD pkgs "shadow" { }; 11 12 chfnRestrict = mkOption { 13 description = mdDoc '' 14 Use chfn SUID to allow non-root users to change their account GECOS information. 15 ''; 16 type = nullOr str; 17 default = null; 18 }; 19 20 settings = mkOption { 21 description = mdDoc '' 22 Config options for the /etc/login.defs file, that defines 23 the site-specific configuration for the shadow password suite. 24 See login.defs(5) man page for available options. 25 ''; 26 type = submodule { 27 freeformType = (pkgs.formats.keyValue { }).type; 28 /* There are three different sources for user/group id ranges, each of which gets 29 used by different programs: 30 - The login.defs file, used by the useradd, groupadd and newusers commands 31 - The update-users-groups.pl file, used by NixOS in the activation phase to 32 decide on which ids to use for declaratively defined users without a static 33 id 34 - Systemd compile time options -Dsystem-uid-max= and -Dsystem-gid-max=, used 35 by systemd for features like ConditionUser=@system and systemd-sysusers 36 */ 37 options = { 38 DEFAULT_HOME = mkOption { 39 description = mdDoc "Indicate if login is allowed if we can't cd to the home directory."; 40 default = "yes"; 41 type = enum [ "yes" "no" ]; 42 }; 43 44 ENCRYPT_METHOD = mkOption { 45 description = mdDoc "This defines the system default encryption algorithm for encrypting passwords."; 46 # The default crypt() method, keep in sync with the PAM default 47 default = "YESCRYPT"; 48 type = enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"]; 49 }; 50 51 SYS_UID_MIN = mkOption { 52 description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers."; 53 default = 400; 54 type = int; 55 }; 56 57 SYS_UID_MAX = mkOption { 58 description = mdDoc "Range of user IDs used for the creation of system users by useradd or newusers."; 59 default = 999; 60 type = int; 61 }; 62 63 UID_MIN = mkOption { 64 description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers."; 65 default = 1000; 66 type = int; 67 }; 68 69 UID_MAX = mkOption { 70 description = mdDoc "Range of user IDs used for the creation of regular users by useradd or newusers."; 71 default = 29999; 72 type = int; 73 }; 74 75 SYS_GID_MIN = mkOption { 76 description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers"; 77 default = 400; 78 type = int; 79 }; 80 81 SYS_GID_MAX = mkOption { 82 description = mdDoc "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers"; 83 default = 999; 84 type = int; 85 }; 86 87 GID_MIN = mkOption { 88 description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers."; 89 default = 1000; 90 type = int; 91 }; 92 93 GID_MAX = mkOption { 94 description = mdDoc "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers."; 95 default = 29999; 96 type = int; 97 }; 98 99 TTYGROUP = mkOption { 100 description = mdDoc '' 101 The terminal permissions: the login tty will be owned by the TTYGROUP group, 102 and the permissions will be set to TTYPERM''; 103 default = "tty"; 104 type = str; 105 }; 106 107 TTYPERM = mkOption { 108 description = mdDoc '' 109 The terminal permissions: the login tty will be owned by the TTYGROUP group, 110 and the permissions will be set to TTYPERM''; 111 default = "0620"; 112 type = str; 113 }; 114 115 # Ensure privacy for newly created home directories. 116 UMASK = mkOption { 117 description = mdDoc "The file mode creation mask is initialized to this value."; 118 default = "077"; 119 type = str; 120 }; 121 }; 122 }; 123 default = { }; 124 }; 125 }; 126 127 users.defaultUserShell = mkOption { 128 description = mdDoc '' 129 This option defines the default shell assigned to user 130 accounts. This can be either a full system path or a shell package. 131 132 This must not be a store path, since the path is 133 used outside the store (in particular in /etc/passwd). 134 ''; 135 example = literalExpression "pkgs.zsh"; 136 type = either path shellPackage; 137 }; 138 }; 139 140 ###### implementation 141 142 config = { 143 assertions = [ 144 { 145 assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX; 146 message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX"; 147 } 148 { 149 assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX; 150 message = "UID_MIN must be less than or equal to UID_MAX"; 151 } 152 { 153 assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX; 154 message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX"; 155 } 156 { 157 assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX; 158 message = "GID_MIN must be less than or equal to GID_MAX"; 159 } 160 ]; 161 162 security.loginDefs.settings.CHFN_RESTRICT = 163 mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict; 164 165 environment.systemPackages = optional config.users.mutableUsers cfg.package 166 ++ optional (types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell 167 ++ optional (cfg.chfnRestrict != null) pkgs.util-linux; 168 169 environment.etc = 170 # Create custom toKeyValue generator 171 # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification 172 let 173 toKeyValue = generators.toKeyValue { 174 mkKeyValue = generators.mkKeyValueDefault { } " "; 175 }; 176 in 177 { 178 # /etc/login.defs: global configuration for pwdutils. 179 # You cannot login without it! 180 "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings); 181 182 # /etc/default/useradd: configuration for useradd. 183 "default/useradd".source = pkgs.writeText "useradd" '' 184 GROUP=100 185 HOME=/home 186 SHELL=${utils.toShellPath config.users.defaultUserShell} 187 ''; 188 }; 189 190 security.pam.services = { 191 chsh = { rootOK = true; }; 192 chfn = { rootOK = true; }; 193 su = { 194 rootOK = true; 195 forwardXAuth = true; 196 logFailures = true; 197 }; 198 passwd = { }; 199 # Note: useradd, groupadd etc. aren't setuid root, so it 200 # doesn't really matter what the PAM config says as long as it 201 # lets root in. 202 useradd.rootOK = true; 203 usermod.rootOK = true; 204 userdel.rootOK = true; 205 groupadd.rootOK = true; 206 groupmod.rootOK = true; 207 groupmems.rootOK = true; 208 groupdel.rootOK = true; 209 login = { 210 startSession = true; 211 allowNullPassword = true; 212 showMotd = true; 213 updateWtmp = true; 214 }; 215 chpasswd = { rootOK = true; }; 216 }; 217 218 security.wrappers = 219 let 220 mkSetuidRoot = source: { 221 setuid = true; 222 owner = "root"; 223 group = "root"; 224 inherit source; 225 }; 226 in 227 { 228 su = mkSetuidRoot "${cfg.package.su}/bin/su"; 229 sg = mkSetuidRoot "${cfg.package.out}/bin/sg"; 230 newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp"; 231 newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap"; 232 newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap"; 233 } 234 // optionalAttrs config.users.mutableUsers { 235 chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh"; 236 passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd"; 237 }; 238 }; 239}