{ config, lib, pkgs, ... }: with lib; let systemUserOpts = { username, ... }: { options = { username = mkOption { type = types.str; description = "The system user's login name."; default = username; }; description = mkOption { type = types.str; description = "Description of this system user's purpose or role"; }; ldap-hashed-password = mkOption { type = types.str; description = "LDAP-formatted hashed password for this user. Generate with slappasswd."; }; }; }; userOpts = { username, ... }: { options = { username = mkOption { type = types.str; description = "The user's login name."; default = username; }; uid = mkOption { type = types.int; description = "Unique UID number for the user."; }; common-name = mkOption { type = types.str; description = "The user's common or given name."; }; primary-group = mkOption { type = types.str; description = "Primary group to which the user belongs."; }; login-shell = mkOption { type = with types; nullOr shellPackage; description = "The user's preferred shell."; }; description = mkOption { type = types.str; default = "Fudo Member"; description = "A description of this user's role."; }; ldap-hashed-passwd = mkOption { type = with types; nullOr str; description = "LDAP-formatted hashed password, used for email and other services. Use slappasswd to generate the properly-formatted password."; default = null; }; login-hashed-passwd = mkOption { type = with types; nullOr str; description = "Hashed password for shell, used for shell access to hosts. Use mkpasswd to generate the properly-formatted password."; default = null; }; ssh-authorized-keys = mkOption { type = with types; listOf str; description = "SSH public keys this user can use to log in."; default = [ ]; }; home-manager-config = mkOption { type = with types; nullOr attrs; description = "Home Manager configuration for the given user."; default = null; }; home-directory = mkOption { type = with types; nullOr str; description = "Default home directory for the given user."; default = null; }; }; }; groupOpts = { group-name, ... }: { options = { group-name = mkOption { type = with types; nullOr str; default = group-name; description = "Group name."; }; description = mkOption { type = types.str; description = "Description of the group or it's purpose."; }; members = mkOption { type = with types; listOf str; default = [ ]; description = "A list of users who are members of the current group."; }; gid = mkOption { type = types.int; description = "GID number of the group."; }; }; }; 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; in { options.fudo = { users = mkOption { type = with types; attrsOf (submodule userOpts); description = "Users"; default = { }; }; groups = mkOption { type = with types; attrsOf (submodule groupOpts); description = "Groups"; default = { }; }; system-users = mkOption { type = with types; attrsOf (submodule systemUserOpts); description = "System users (probably not what you're looking for!)"; default = { }; }; }; config = let local-host = config.instance.hostname; local-domain = config.fudo.hosts.${local-host}.domain; local-site = config.fudo.hosts.${local-host}.site; host-user-list = config.fudo.hosts."${local-host}".local-users; domain-user-list = config.fudo.domains."${local-domain}".local-users; local-users = getAttrs (host-user-list ++ domain-user-list) config.fudo.users; host-admin-list = config.fudo.hosts."${local-host}".local-admins; domain-admin-list = config.fudo.domains."${local-domain}".local-admins; site-admin-list = config.fudo.sites."${local-site}".local-admins; local-admins = host-admin-list ++ domain-admin-list ++ site-admin-list; host-group-list = config.fudo.hosts."${local-host}".local-groups; domain-group-list = config.fudo.domains."${local-domain}".local-groups; site-group-list = config.fudo.sites."${local-site}".local-groups; local-groups = getAttrs (host-group-list ++ domain-group-list ++ site-group-list) config.fudo.groups; 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; }; 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; }) local-users; groups = (mapAttrs (groupname: groupOpts: { gid = groupOpts.gid; members = filterExistingUsers local-users groupOpts.members; }) local-groups) // { wheel = { members = local-admins; }; }; }; home-manager.users = let home-manager-users = filterAttrs (username: userOpts: userOpts.home-manager-config != null) local-users; in mapAttrs (username: userOpts: userOpts.home-manager-config) home-manager-users; }; }