diff options
Diffstat (limited to 'nixos/modules/config/users-groups.nix')
-rw-r--r-- | nixos/modules/config/users-groups.nix | 128 |
1 files changed, 81 insertions, 47 deletions
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index d172ddb6bca..9d48edf2f26 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -8,23 +8,28 @@ let cfg = config.users; passwordDescription = '' - The options <literal>hashedPassword</literal>, - <literal>password</literal> and <literal>passwordFile</literal> + The options <option>hashedPassword</option>, + <option>password</option> and <option>passwordFile</option> controls what password is set for the user. - <literal>hashedPassword</literal> overrides both - <literal>password</literal> and <literal>passwordFile</literal>. - <literal>password</literal> overrides <literal>passwordFile</literal>. + <option>hashedPassword</option> overrides both + <option>password</option> and <option>passwordFile</option>. + <option>password</option> overrides <option>passwordFile</option>. If none of these three options are set, no password is assigned to the user, and the user will not be able to do password logins. - If the option <literal>users.mutableUsers</literal> is true, the + If the option <option>users.mutableUsers</option> is true, the password defined in one of the three options will only be set when the user is created for the first time. After that, you are free to change the password with the ordinary user management commands. If - <literal>users.mutableUsers</literal> is false, you cannot change + <option>users.mutableUsers</option> is false, you cannot change user passwords, they will always be set according to the password options. ''; + hashedPasswordDescription = '' + To generate hashed password install <literal>mkpassword</literal> + package and run <literal>mkpasswd -m sha-512</literal>. + ''; + userOpts = { name, config, ... }: { options = { @@ -105,7 +110,7 @@ let shell = mkOption { type = types.str; - default = "/run/current-system/sw/sbin/nologin"; + default = "/run/current-system/sw/bin/nologin"; description = "The path to the user's shell."; }; @@ -155,7 +160,7 @@ let default = false; description = '' If true, the user's shell will be set to - <literal>cfg.defaultUserShell</literal>. + <option>users.defaultUserShell</option>. ''; }; @@ -163,8 +168,9 @@ let type = with types; uniq (nullOr str); default = null; description = '' - Specifies the (hashed) password for the user. + Specifies the hashed password for the user. ${passwordDescription} + ${hashedPasswordDescription} ''; }; @@ -184,13 +190,46 @@ let type = with types; uniq (nullOr string); default = null; description = '' - The path to a file that contains the user's password. The password + The full path to a file that contains the user's password. The password file is read on each system activation. The file should contain exactly one line, which should be the password in an encrypted form that is suitable for the <literal>chpasswd -e</literal> command. ${passwordDescription} ''; }; + + initialHashedPassword = mkOption { + type = with types; uniq (nullOr str); + default = null; + description = '' + Specifies the initial hashed password for the user, i.e. the + hashed password assigned if the user does not already + exist. If <option>users.mutableUsers</option> is true, the + password can be changed subsequently using the + <command>passwd</command> command. Otherwise, it's + equivalent to setting the <option>password</option> option. + + ${hashedPasswordDescription} + ''; + }; + + initialPassword = mkOption { + type = with types; uniq (nullOr str); + default = null; + description = '' + Specifies the initial password for the user, i.e. the + password assigned if the user does not already exist. If + <option>users.mutableUsers</option> is true, the password + can be changed subsequently using the + <command>passwd</command> command. Otherwise, it's + equivalent to setting the <option>password</option> + option. The same caveat applies: the password specified here + is world-readable in the Nix store, so it should only be + used for guest accounts or passwords that will be changed + promptly. + ''; + }; + }; config = mkMerge @@ -204,6 +243,14 @@ let useDefaultShell = mkDefault true; isSystemUser = mkDefault false; }) + # If !mutableUsers, setting ‘initialPassword’ is equivalent to + # setting ‘password’ (and similarly for hashed passwords). + (mkIf (!cfg.mutableUsers && config.initialPassword != null) { + password = mkDefault config.initialPassword; + }) + (mkIf (!cfg.mutableUsers && config.initialHashedPassword != null) { + hashedPassword = mkDefault config.initialHashedPassword; + }) ]; }; @@ -276,23 +323,17 @@ let }; }; - filterNull = a: filter (x: hasAttr a x && getAttr a x != null); - - sortOn "gid" (filterNull "gid" (attrValues cfg.extraGroups)) - sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)) mkSubuidEntry = user: concatStrings ( map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n") - user.subUidRanges); + user.subUidRanges); - subuidFile = concatStrings (map mkSubuidEntry ( - sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)))); + subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.extraUsers)); mkSubgidEntry = user: concatStrings ( map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n") user.subGidRanges); - subgidFile = concatStrings (map mkSubgidEntry ( - sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)))); + subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.extraUsers)); idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }: let @@ -307,18 +348,19 @@ let uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.extraUsers) "uid"; gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.extraGroups) "gid"; - spec = builtins.toFile "users-groups.json" (builtins.toJSON { + spec = pkgs.writeText "users-groups.json" (builtins.toJSON { inherit (cfg) mutableUsers; users = mapAttrsToList (n: u: { inherit (u) name uid group description home shell createHome isSystemUser - password passwordFile hashedPassword; + password passwordFile hashedPassword + initialPassword initialHashedPassword; }) cfg.extraUsers; groups = mapAttrsToList (n: g: { inherit (g) name gid; - members = mapAttrsToList (n: u: u.name) ( + members = g.members ++ (mapAttrsToList (n: u: u.name) ( filterAttrs (n: u: elem g.name u.extraGroups) cfg.extraUsers - ); + )); }) cfg.extraGroups; }); @@ -332,21 +374,24 @@ in { type = types.bool; default = true; description = '' - If true, you are free to add new users and groups to the system + If set to <literal>true</literal>, you are free to add new users and groups to the system with the ordinary <literal>useradd</literal> and <literal>groupadd</literal> commands. On system activation, the existing contents of the <literal>/etc/passwd</literal> and <literal>/etc/group</literal> files will be merged with the contents generated from the <literal>users.extraUsers</literal> and - <literal>users.extraGroups</literal> options. If - <literal>mutableUsers</literal> is false, the contents of the user and - group files will simply be replaced on system activation. This also - holds for the user passwords; if this option is false, all changed - passwords will be reset according to the - <literal>users.extraUsers</literal> configuration on activation. If - this option is true, the initial password for a user will be set + <literal>users.extraGroups</literal> options. + The initial password for a user will be set according to <literal>users.extraUsers</literal>, but existing passwords will not be changed. + + <warning><para> + If set to <literal>false</literal>, the contents of the user and + group files will simply be replaced on system activation. This also + holds for the user passwords; all changed + passwords will be reset according to the + <literal>users.extraUsers</literal> configuration on activation. + </para></warning> ''; }; @@ -392,24 +437,12 @@ in { options = [ groupOpts ]; }; + # FIXME: obsolete - will remove. security.initialRootPassword = mkOption { type = types.str; default = "!"; example = ""; - description = '' - The (hashed) password for the root account set on initial - installation. The empty string denotes that root can login - locally without a password (but not via remote services such - as SSH, or indirectly via <command>su</command> or - <command>sudo</command>). The string <literal>!</literal> - prevents root from logging in using a password. - Note that setting this option sets - <literal>users.extraUsers.root.hashedPassword</literal>. - Also, if <literal>users.mutableUsers</literal> is false - you cannot change the root password manually, so in that case - the name of this option is a bit misleading, since it will define - the root password beyond the user initialisation phase. - ''; + visible = false; }; }; @@ -427,7 +460,7 @@ in { shell = mkDefault cfg.defaultUserShell; group = "root"; extraGroups = [ "grsecurity" ]; - hashedPassword = mkDefault config.security.initialRootPassword; + initialHashedPassword = mkDefault config.security.initialRootPassword; }; nobody = { uid = ids.uids.nobody; @@ -456,6 +489,7 @@ in { utmp.gid = ids.gids.utmp; adm.gid = ids.gids.adm; grsecurity.gid = ids.gids.grsecurity; + input.gid = ids.gids.input; }; system.activationScripts.users = stringAfter [ "etc" ] |