2009-01-02 16:07:01 +00:00
|
|
|
{pkgs, config, ...}:
|
2007-06-08 16:41:12 +01:00
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
with pkgs.lib;
|
2009-01-02 16:07:01 +00:00
|
|
|
|
|
|
|
let
|
2009-09-02 18:35:24 +01:00
|
|
|
|
2009-05-29 15:25:56 +01:00
|
|
|
ids = config.ids;
|
2007-06-08 16:41:12 +01:00
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
|
2007-11-16 13:26:34 +00:00
|
|
|
# User accounts to be created/updated by NixOS.
|
|
|
|
users =
|
2007-06-08 16:41:12 +01:00
|
|
|
let
|
|
|
|
defaultUsers =
|
2009-09-02 18:35:24 +01:00
|
|
|
[ { name = "root";
|
2007-06-08 16:41:12 +01:00
|
|
|
uid = ids.uids.root;
|
|
|
|
description = "System administrator";
|
|
|
|
home = "/root";
|
2009-05-28 13:24:56 +01:00
|
|
|
shell = config.users.defaultUserShell;
|
2007-11-12 14:59:23 +00:00
|
|
|
group = "root";
|
2007-06-08 16:41:12 +01:00
|
|
|
}
|
|
|
|
{ name = "nobody";
|
|
|
|
uid = ids.uids.nobody;
|
|
|
|
description = "Unprivileged account (don't use!)";
|
|
|
|
}
|
|
|
|
];
|
2009-12-13 15:29:42 +00:00
|
|
|
|
2007-06-08 16:41:12 +01:00
|
|
|
addAttrs =
|
|
|
|
{ name
|
|
|
|
, description
|
|
|
|
, uid ? ""
|
|
|
|
, group ? "nogroup"
|
|
|
|
, extraGroups ? []
|
|
|
|
, home ? "/var/empty"
|
2009-05-28 13:24:56 +01:00
|
|
|
, shell ? (if useDefaultShell then config.users.defaultUserShell else "/noshell")
|
2007-11-16 13:26:34 +00:00
|
|
|
, createHome ? false
|
|
|
|
, useDefaultShell ? false
|
2009-09-02 18:35:24 +01:00
|
|
|
, password ? null
|
2007-06-08 16:41:12 +01:00
|
|
|
}:
|
2009-09-02 18:35:24 +01:00
|
|
|
{ inherit name description uid group extraGroups home shell createHome password; };
|
2007-06-08 16:41:12 +01:00
|
|
|
|
2010-03-11 16:50:08 +00:00
|
|
|
in map addAttrs (defaultUsers ++ config.users.extraUsers);
|
2007-06-08 16:41:12 +01:00
|
|
|
|
|
|
|
|
2007-11-16 13:26:34 +00:00
|
|
|
# Groups to be created/updated by NixOS.
|
|
|
|
groups =
|
2007-06-10 21:13:12 +01:00
|
|
|
let
|
|
|
|
defaultGroups =
|
2009-09-02 18:35:24 +01:00
|
|
|
[ { name = "root";
|
2007-06-10 21:13:12 +01:00
|
|
|
gid = ids.gids.root;
|
|
|
|
}
|
2007-08-16 16:09:06 +01:00
|
|
|
{ name = "wheel";
|
|
|
|
gid = ids.gids.wheel;
|
|
|
|
}
|
2008-07-02 19:03:43 +01:00
|
|
|
{ name = "disk";
|
|
|
|
gid = ids.gids.disk;
|
|
|
|
}
|
|
|
|
{ name = "kmem";
|
|
|
|
gid = ids.gids.kmem;
|
|
|
|
}
|
|
|
|
{ name = "tty";
|
|
|
|
gid = ids.gids.tty;
|
|
|
|
}
|
|
|
|
{ name = "floppy";
|
|
|
|
gid = ids.gids.floppy;
|
|
|
|
}
|
|
|
|
{ name = "uucp";
|
|
|
|
gid = ids.gids.uucp;
|
|
|
|
}
|
|
|
|
{ name = "lp";
|
|
|
|
gid = ids.gids.lp;
|
|
|
|
}
|
2009-08-11 10:17:30 +01:00
|
|
|
{ name = "cdrom";
|
|
|
|
gid = ids.gids.cdrom;
|
|
|
|
}
|
|
|
|
{ name = "tape";
|
|
|
|
gid = ids.gids.tape;
|
|
|
|
}
|
|
|
|
{ name = "video";
|
|
|
|
gid = ids.gids.video;
|
|
|
|
}
|
|
|
|
{ name = "dialout";
|
|
|
|
gid = ids.gids.dialout;
|
|
|
|
}
|
2007-06-10 21:13:12 +01:00
|
|
|
{ name = "nogroup";
|
|
|
|
gid = ids.gids.nogroup;
|
|
|
|
}
|
|
|
|
{ name = "users";
|
|
|
|
gid = ids.gids.users;
|
|
|
|
}
|
|
|
|
{ name = "nixbld";
|
|
|
|
gid = ids.gids.nixbld;
|
|
|
|
}
|
2010-04-22 14:56:26 +01:00
|
|
|
{ name = "utmp";
|
|
|
|
gid = ids.gids.utmp;
|
|
|
|
}
|
2007-06-10 21:13:12 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
addAttrs =
|
|
|
|
{ name, gid ? "" }:
|
|
|
|
{ inherit name gid; };
|
|
|
|
|
2008-11-18 18:00:09 +00:00
|
|
|
in map addAttrs (defaultGroups ++ config.users.extraGroups);
|
2007-06-08 16:41:12 +01:00
|
|
|
|
2009-01-02 16:07:01 +00:00
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
# Note: the 'X' in front of the password is to distinguish between
|
|
|
|
# having an empty password, and not having a password.
|
|
|
|
serializedUser = u: "${u.name}\n${u.description}\n${toString u.uid}\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";
|
2009-01-02 16:07:01 +00:00
|
|
|
serializedGroup = g: "${g.name}\n${toString g.gid}";
|
2009-09-02 18:35:24 +01:00
|
|
|
|
2009-03-06 12:26:16 +00:00
|
|
|
# keep this extra file so that cat can be used to pass special chars such as "`" which is used in the avahi daemon
|
2009-09-02 18:35:24 +01:00
|
|
|
usersFile = pkgs.writeText "users" (concatStrings (map serializedUser users));
|
|
|
|
|
2009-01-02 16:07:01 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
###### interface
|
2009-01-02 16:07:01 +00:00
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
options = {
|
|
|
|
|
|
|
|
users.extraUsers = mkOption {
|
|
|
|
default = [];
|
|
|
|
example =
|
|
|
|
[ { name = "alice";
|
|
|
|
uid = 1234;
|
|
|
|
description = "Alice";
|
|
|
|
home = "/home/alice";
|
|
|
|
createHome = true;
|
|
|
|
group = "users";
|
|
|
|
extraGroups = ["wheel"];
|
|
|
|
shell = "/bin/sh";
|
|
|
|
password = "foobar";
|
|
|
|
}
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
Additional user accounts to be created automatically by the system.
|
|
|
|
'';
|
|
|
|
};
|
2009-01-02 16:07:01 +00:00
|
|
|
|
2009-09-02 18:35:24 +01:00
|
|
|
users.extraGroups = mkOption {
|
|
|
|
default = [];
|
|
|
|
example =
|
|
|
|
[ { name = "students";
|
|
|
|
gid = 1001;
|
|
|
|
}
|
|
|
|
];
|
|
|
|
description = ''
|
|
|
|
Additional groups to be created automatically by the system.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
###### implementation
|
|
|
|
|
|
|
|
config = {
|
|
|
|
|
2010-09-13 16:41:38 +01:00
|
|
|
system.activationScripts.rootPasswd = stringAfter [ "etc" ]
|
|
|
|
''
|
|
|
|
# If there is no password file yet, create a root account with an
|
|
|
|
# empty password.
|
|
|
|
if ! test -e /etc/passwd; then
|
|
|
|
rootHome=/root
|
|
|
|
touch /etc/passwd; chmod 0644 /etc/passwd
|
|
|
|
touch /etc/group; chmod 0644 /etc/group
|
|
|
|
touch /etc/shadow; chmod 0600 /etc/shadow
|
|
|
|
# Can't use useradd, since it complains that it doesn't know us
|
|
|
|
# (bootstrap problem!).
|
|
|
|
echo "root:x:0:0:System administrator:$rootHome:${config.users.defaultUserShell}" >> /etc/passwd
|
|
|
|
echo "root::::::::" >> /etc/shadow
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
|
|
|
system.activationScripts.users = stringAfter [ "groups" ]
|
2009-09-02 18:35:24 +01:00
|
|
|
''
|
2009-12-16 13:35:03 +00:00
|
|
|
echo "updating users..."
|
|
|
|
|
2009-03-06 12:26:16 +00:00
|
|
|
cat ${usersFile} | while true; do
|
2009-01-02 16:07:01 +00:00
|
|
|
read name || break
|
|
|
|
read description
|
|
|
|
read uid
|
|
|
|
read group
|
|
|
|
read extraGroups
|
|
|
|
read home
|
|
|
|
read shell
|
|
|
|
read createHome
|
2009-09-02 18:35:24 +01:00
|
|
|
read password
|
2009-01-02 16:07:01 +00:00
|
|
|
|
|
|
|
if ! curEnt=$(getent passwd "$name"); then
|
|
|
|
useradd --system \
|
|
|
|
--comment "$description" \
|
|
|
|
''${uid:+--uid $uid} \
|
|
|
|
--gid "$group" \
|
|
|
|
--groups "$extraGroups" \
|
|
|
|
--home "$home" \
|
|
|
|
--shell "$shell" \
|
2010-06-02 22:10:48 +01:00
|
|
|
''${createHome:+--create-home} \
|
|
|
|
"$name"
|
2009-09-02 18:35:24 +01:00
|
|
|
if test "''${password:0:1}" = 'X'; then
|
2010-06-03 00:02:09 +01:00
|
|
|
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"
|
2009-09-02 18:35:24 +01:00
|
|
|
fi
|
2009-01-02 16:07:01 +00:00
|
|
|
else
|
|
|
|
#echo "updating user $name..."
|
|
|
|
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
|
|
|
|
prevUid=$3
|
|
|
|
prevHome=$6
|
|
|
|
# Don't change the UID if it's the same, otherwise usermod
|
|
|
|
# will complain.
|
|
|
|
if test "$prevUid" = "$uid"; then unset uid; fi
|
|
|
|
# Don't change the home directory if it's the same to prevent
|
|
|
|
# unnecessary warnings about logged in users.
|
|
|
|
if test "$prevHome" = "$home"; then unset home; fi
|
|
|
|
usermod \
|
|
|
|
--comment "$description" \
|
|
|
|
''${uid:+--uid $uid} \
|
|
|
|
--gid "$group" \
|
|
|
|
--groups "$extraGroups" \
|
|
|
|
''${home:+--home "$home"} \
|
2010-06-02 22:10:48 +01:00
|
|
|
--shell "$shell" \
|
|
|
|
"$name"
|
2009-12-16 13:35:03 +00:00
|
|
|
fi
|
|
|
|
|
2009-03-06 12:26:16 +00:00
|
|
|
done
|
2010-09-13 16:41:38 +01:00
|
|
|
'';
|
2009-01-02 16:07:01 +00:00
|
|
|
|
2010-09-13 16:41:38 +01:00
|
|
|
system.activationScripts.groups = stringAfter [ "rootPasswd" "binsh" "etc" "var" ]
|
2009-09-02 18:35:24 +01:00
|
|
|
''
|
2009-12-16 13:35:03 +00:00
|
|
|
echo "updating groups..."
|
|
|
|
|
2009-01-02 16:07:01 +00:00
|
|
|
while true; do
|
|
|
|
read name || break
|
|
|
|
read gid
|
|
|
|
|
|
|
|
if ! curEnt=$(getent group "$name"); then
|
|
|
|
groupadd --system \
|
2010-06-02 22:10:48 +01:00
|
|
|
''${gid:+--gid $gid} \
|
|
|
|
"$name"
|
2009-01-02 16:07:01 +00:00
|
|
|
else
|
|
|
|
#echo "updating group $name..."
|
|
|
|
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
|
|
|
|
prevGid=$3
|
|
|
|
if test -n "$gid" -a "$prevGid" != "$gid"; then
|
2010-06-02 22:10:48 +01:00
|
|
|
groupmod --gid $gid "$name"
|
2009-01-02 16:07:01 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done <<EndOfGroupList
|
|
|
|
${concatStringsSep "\n" (map serializedGroup groups)}
|
|
|
|
EndOfGroupList
|
2010-09-13 16:41:38 +01:00
|
|
|
'';
|
2007-06-08 16:41:12 +01:00
|
|
|
|
2009-01-02 16:07:01 +00:00
|
|
|
};
|
2009-09-02 18:35:24 +01:00
|
|
|
|
2007-11-09 18:49:45 +00:00
|
|
|
}
|