Add user option ‘isAlias’ to allow one user account to alias another

This commit is contained in:
Eelco Dolstra 2012-10-23 13:35:06 +02:00
parent c8628e0293
commit 7efde0740e

@ -8,74 +8,74 @@ let
users = config.users; users = config.users;
userOpts = { name, config, ... }: { userOpts = { name, config, ... }: {
options = { options = {
name = mkOption { name = mkOption {
type = with types; uniq string; type = with types; uniq string;
description = "The name of the user account. If undefined, the name of the attribute set will be used."; description = "The name of the user account. If undefined, the name of the attribute set will be used.";
}; };
description = mkOption { description = mkOption {
type = with types; uniq string; type = with types; uniq string;
default = ""; default = "";
description = "A short description of the user account."; description = "A short description of the user account.";
}; };
uid = mkOption { uid = mkOption {
type = with types; uniq (nullOr int); type = with types; uniq (nullOr int);
default = null; default = null;
description = "The account UID. If undefined, NixOS will select a free UID."; description = "The account UID. If undefined, NixOS will select a free UID.";
}; };
group = mkOption { group = mkOption {
type = with types; uniq string; type = with types; uniq string;
default = "nogroup"; default = "nogroup";
description = "The user's primary group."; description = "The user's primary group.";
}; };
extraGroups = mkOption { extraGroups = mkOption {
type = types.listOf types.string; type = types.listOf types.string;
default = []; default = [];
description = "The user's auxiliary groups."; description = "The user's auxiliary groups.";
}; };
home = mkOption { home = mkOption {
type = with types; uniq string; type = with types; uniq string;
default = "/var/empty"; default = "/var/empty";
description = "The user's home directory."; description = "The user's home directory.";
}; };
shell = mkOption { shell = mkOption {
type = with types; uniq string; type = with types; uniq string;
default = "/run/current-system/sw/sbin/nologin"; default = "/run/current-system/sw/sbin/nologin";
description = "The path to the user's shell."; description = "The path to the user's shell.";
}; };
createHome = mkOption { createHome = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "If true, the home directory will be created automatically."; description = "If true, the home directory will be created automatically.";
}; };
useDefaultShell = mkOption { useDefaultShell = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>."; description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>.";
}; };
password = mkOption { password = mkOption {
type = with types; uniq (nullOr string); type = with types; uniq (nullOr string);
default = null; default = null;
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest."; description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
}; };
isSystemUser = mkOption { isSystemUser = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
description = "Indicates if the user is a system user or not."; description = "Indicates if the user is a system user or not.";
}; };
createUser = mkOption { createUser = mkOption {
type = types.bool; type = types.bool;
default = true; default = true;
@ -85,7 +85,13 @@ let
then not modify any of the basic properties for the user account. then not modify any of the basic properties for the user account.
"; ";
}; };
isAlias = mkOption {
type = types.bool;
default = false;
description = "If true, the UID of this user is not required to be unique and can thus alias another user.";
};
}; };
config = { config = {
@ -93,41 +99,41 @@ let
uid = mkDefault (attrByPath [name] null ids.uids); uid = mkDefault (attrByPath [name] null ids.uids);
shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell); shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
}; };
}; };
groupOpts = { name, config, ... }: { groupOpts = { name, config, ... }: {
options = { options = {
name = mkOption { name = mkOption {
type = with types; uniq string; type = with types; uniq string;
description = "The name of the group. If undefined, the name of the attribute set will be used."; description = "The name of the group. If undefined, the name of the attribute set will be used.";
}; };
gid = mkOption { gid = mkOption {
type = with types; uniq (nullOr int); type = with types; uniq (nullOr int);
default = null; default = null;
description = "The GID of the group. If undefined, NixOS will select a free GID."; description = "The GID of the group. If undefined, NixOS will select a free GID.";
}; };
}; };
config = { config = {
name = mkDefault name; name = mkDefault name;
gid = mkDefault (attrByPath [name] null ids.gids); gid = mkDefault (attrByPath [name] null ids.gids);
}; };
}; };
# Note: the 'X' in front of the password is to distinguish between # Note: the 'X' in front of the password is to distinguish between
# having an empty password, and not having a password. # having an empty password, and not having a password.
serializedUser = userName: let u = getAttr userName config.users.extraUsers; in "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${if u.createUser then "yes" else "no"}\n"; serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n";
# keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
usersFile = pkgs.writeText "users" ( usersFile = pkgs.writeText "users" (
concatMapStrings serializedUser (attrNames config.users.extraUsers) let
); p = partition (u: u.isAlias) (attrValues config.users.extraUsers);
in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right));
in in
@ -243,8 +249,9 @@ in
read password read password
read isSystemUser read isSystemUser
read createUser read createUser
read isAlias
if ! test "$createUser" = "yes"; then if [ -z "$createUser" ]; then
continue continue
fi fi
@ -257,6 +264,7 @@ in
--home "$home" \ --home "$home" \
--shell "$shell" \ --shell "$shell" \
''${createHome:+--create-home} \ ''${createHome:+--create-home} \
''${isAlias:+--non-unique} \
"$name" "$name"
if test "''${password:0:1}" = 'X'; then if test "''${password:0:1}" = 'X'; then
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name" (echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"