{ config, lib, pkgs, ... }: with lib; let user = import ../types/user.nix { inherit lib; }; list-includes = list: el: isNull (findFirst (this: this == el) null list); filterExistingUsers = users: group-members: let user-list = attrNames users; in filter (username: list-includes user-list username) group-members; ensure-group-directory = group: dir: '' if [[ -d ${dir} ]]; then GROUP="$(stat --format '%G' "${dir}")" if [[ "$GROUP" = "${group}" ]]; then echo "${dir} exists and belongs to ${group}" exit 0 else echo "setting ownership of ${dir} to ${group}" chgrp ${group} ${dir} chmod g+rx ${dir} fi elif [[ ! -e ${dir} ]]; then echo "creating ${dir} and setting ownership to ${group}" mkdir ${dir} chgrp ${group} ${dir} chmod g+rx ${dir} elif [[ -e ${dir} && ! -d ${dir} ]]; then echo "unable to create directory ${dir}, object exists" exit 2 else echo "unknown error creating ${dir}" exit 3 fi ''; ensure-group-dirs-script = group: dirs: concatStringsSep "\n" (map (ensure-group-directory group) dirs); hostname = config.instance.hostname; host-cfg = config.fudo.hosts.${hostname}; in { options = with types; { fudo = { users = mkOption { type = attrsOf (submodule user.userOpts); description = "Users"; default = { }; }; groups = mkOption { type = attrsOf (submodule user.groupOpts); description = "Groups"; default = { }; }; system-users = mkOption { type = attrsOf (submodule user.systemUserOpts); description = "System users (probably not what you're looking for!)"; default = { }; }; }; }; imports = [ ./users-common.nix ]; config = let sys = config.instance; in { fudo.auth.ldap-server = let ldapUsers = (filterAttrs (username: userOpts: userOpts.ldap-hashed-password != null)) config.fudo.users; in { users = mapAttrs (username: userOpts: { uid = userOpts.uid; group = userOpts.primary-group; common-name = userOpts.common-name; hashed-password = userOpts.ldap-hashed-password; }) ldapUsers; groups = mapAttrs (groupname: groupOpts: { gid = groupOpts.gid-number; description = groupOpts.description; members = filterExistingUsers ldapUsers groupOpts.members; }) config.fudo.groups; system-users = mapAttrs (username: userOpts: { description = userOpts.description; hashed-password = userOpts.ldap-hashed-passwd; }) config.fudo.system-users; }; programs.ssh.extraConfig = mkAfter '' IdentityFile %h/.ssh/id_rsa IdentityFile /etc/ssh/private_keys.d/%u.key ''; environment.etc = mapAttrs' (username: userOpts: nameValuePair "ssh/private_keys.d/${username}" { text = concatStringsSep "\n" (map (keypair: readFile keypair.public-key) userOpts.ssh-keys); }) sys.local-users; users = { users = mapAttrs (username: userOpts: { isNormalUser = true; uid = userOpts.uid; createHome = true; description = userOpts.common-name; group = userOpts.primary-group; home = if (userOpts.home-directory != null) then userOpts.home-directory else "/home/${userOpts.primary-group}/${username}"; hashedPassword = userOpts.login-hashed-passwd; openssh.authorizedKeys.keys = userOpts.ssh-authorized-keys; }) sys.local-users; groups = (mapAttrs (groupname: groupOpts: { gid = groupOpts.gid; members = filterExistingUsers sys.local-users groupOpts.members; }) sys.local-groups) // { wheel = { members = sys.local-admins; }; docker = mkIf (host-cfg.docker-server) { members = sys.local-admins; }; }; }; home-manager.useGlobalPkgs = true; # home-manager.useGlobalPkgs = { # useGlobalPkgs = true; # users = let # home-manager-users = # filterAttrs (username: userOpts: userOpts.home-manager-generator != null) # sys.local-users; # in mapAttrs (username: userOpts: userOpts.home-manager-generator { # enable-gui = host-cfg.enable-gui; # }) home-manager-users; # }; # Group home directories have to exist, otherwise users can't log in systemd.services = let ensure-group-directories = group: nameValuePair "ensure-group-directories-${group}" { script = ensure-group-dirs-script group [ "/home/${group}" ]; wantedBy = [ "multi-user.target" ]; requires = [ "local-fs.target" ]; after = [ "remote-fs.target" ]; }; groups-with-members = attrNames (filterAttrs (group: groupOpts: (length groupOpts.members) > 0) sys.local-groups); in listToAttrs (map ensure-group-directories groups-with-members); }; }