From f6e600c20d6a97ebeda23fa2bb5621646222b2b0 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Sat, 2 Jan 2021 20:53:17 +0100 Subject: sif: import config --- modules/uucp.nix | 391 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 modules/uucp.nix (limited to 'modules/uucp.nix') diff --git a/modules/uucp.nix b/modules/uucp.nix new file mode 100644 index 00000000..8d8ac1a2 --- /dev/null +++ b/modules/uucp.nix @@ -0,0 +1,391 @@ +{ flake, config, lib, pkgs, ... }: + +with lib; + +let + portSpec = name: node: concatStringsSep "\n" (map (port: '' + port ${name}.${port} + type pipe + protocol ${node.protocols} + reliable true + command ${pkgs.openssh}/bin/ssh -x -o batchmode=yes ${name}.${port} + '') node.hostnames); + sysSpec = name: node: '' + system ${name} + time any + chat-seven-bit false + chat . "" + protocol ${node.protocols} + command-path ${concatStringsSep " " cfg.commandPath} + commands ${concatStringsSep " " node.commands} + ${concatStringsSep "\nalternate\n" (map (port: '' + port ${name}.${port} + '') node.hostnames)} + ''; + sshConfig = name: node: concatStringsSep "\n" (map (port: '' + Host ${name}.${port} + Hostname ${port} + IdentitiesOnly Yes + IdentityFile ${cfg.sshKeyDir}/${name} + '') node.hostnames); + sshKeyGen = name: node: '' + if [[ ! -e ${cfg.sshKeyDir}/${name} ]]; then + ${pkgs.openssh}/bin/ssh-keygen ${escapeShellArgs node.generateKey} -f ${cfg.sshKeyDir}/${name} + fi + ''; + restrictKey = key: '' + restrict,command="${chat}" ${key} + ''; + chat = pkgs.writeScript "chat" '' + #!${pkgs.stdenv.shell} + + echo . + exec ${config.security.wrapperDir}/uucico + ''; + + nodeCfg = { + options = { + commands = mkOption { + type = types.listOf types.str; + default = cfg.defaultCommands; + description = "Commands to allow for this remote"; + }; + + protocols = mkOption { + type = types.separatedString ""; + default = cfg.defaultProtocols; + description = "UUCP protocols to use for this remote"; + }; + + publicKeys = mkOption { + type = types.listOf types.str; + default = []; + description = "SSH client public keys for this node"; + }; + + generateKey = mkOption { + type = types.listOf types.str; + default = [ "-t" "ed25519" "-N" "" ]; + description = "Arguments to pass to `ssh-keygen` to generate a keypair for communication with this host"; + }; + + hostnames = mkOption { + type = types.listOf types.str; + default = []; + description = "Hostnames to try in order when connecting"; + }; + }; + }; + + cfg = config.services.uucp; +in { + options = { + services.uucp = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + If enabled we set up an account accesible via uucp over ssh + ''; + }; + + nodeName = mkOption { + type = types.str; + default = "nixos"; + description = "uucp node name"; + }; + + sshUser = mkOption { + type = types.attrs; + default = {}; + description = "Overrides for the local uucp linux-user"; + }; + + extraSSHConfig = mkOption { + type = types.str; + default = ""; + description = "Extra SSH config"; + }; + + remoteNodes = mkOption { + type = types.attrsOf (types.submodule nodeCfg); + default = {}; + description = '' + Ports to set up + Names will probably need to be configured in sshConfig + ''; + }; + + commandPath = mkOption { + type = types.listOf types.path; + default = [ "${pkgs.rmail}/bin" ]; + description = '' + Command search path for all systems + ''; + }; + + defaultCommands = mkOption { + type = types.listOf types.str; + default = ["rmail"]; + description = "Commands allowed for remotes without explicit override"; + }; + + defaultProtocols = mkOption { + type = types.separatedString ""; + default = "te"; + description = "UUCP protocol to use within ssh unless overriden"; + }; + + incomingProtocols = mkOption { + type = types.separatedString ""; + default = "te"; + description = "UUCP protocols to use when called"; + }; + + homeDir = mkOption { + type = types.path; + default = "/var/uucp"; + description = "Home of the uucp user"; + }; + + sshKeyDir = mkOption { + type = types.path; + default = "${cfg.homeDir}/.ssh/"; + description = "Directory to store ssh keypairs"; + }; + + spoolDir = mkOption { + type = types.path; + default = "/var/spool/uucp"; + description = "Spool directory"; + }; + + lockDir = mkOption { + type = types.path; + default = "/var/spool/uucp"; + description = "Lock directory"; + }; + + pubDir = mkOption { + type = types.path; + default = "/var/spool/uucppublic"; + description = "Public directory"; + }; + + logFile = mkOption { + type = types.path; + default = "/var/log/uucp"; + description = "Log file"; + }; + + statFile = mkOption { + type = types.path; + default = "/var/log/uucp.stat"; + description = "Statistics file"; + }; + + debugFile = mkOption { + type = types.path; + default = "/var/log/uucp.debug"; + description = "Debug file"; + }; + + interval = mkOption { + type = types.nullOr types.str; + default = "1h"; + description = '' + Specification of when to run `uucico' in format used by systemd timers + The default is to do so every hour + ''; + }; + + nmDispatch = mkOption { + type = types.bool; + default = config.networking.networkmanager.enable; + description = '' + Install a network-manager dispatcher script to automatically + call all remotes when networking is available + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = '' + run-uuxqt 1 + ''; + description = "Extra configuration to append verbatim to `/etc/uucp/config'"; + }; + + extraSys = mkOption { + type = types.lines; + default = '' + protocol-parameter g packet-size 4096 + ''; + description = "Extra configuration to prepend verbatim to `/etc/uucp/sys`"; + }; + }; + }; + + config = mkIf cfg.enable { + environment.etc."uucp/config" = { + text = '' + hostname ${cfg.nodeName} + + spool ${cfg.spoolDir} + lockdir ${cfg.lockDir} + pubdir ${cfg.pubDir} + logfile ${cfg.logFile} + statfile ${cfg.statFile} + debugfile ${cfg.debugFile} + + ${cfg.extraConfig} + ''; + }; + + users.users."uucp" = { + name = "uucp"; + isSystemUser = true; + isNormalUser = false; + createHome = true; + home = cfg.homeDir; + description = "User for uucp over ssh"; + useDefaultShell = true; + openssh.authorizedKeys.keys = map restrictKey (concatLists (mapAttrsToList (name: node: node.publicKeys) cfg.remoteNodes)); + } // cfg.sshUser; + + system.activationScripts."uucp-sshconfig" = '' + mkdir -p ${config.users.users."uucp".home}/.ssh + chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${config.users.users."uucp".home}/.ssh + chmod 700 ${config.users.users."uucp".home}/.ssh + ln -fs ${builtins.toFile "ssh-config" '' + ${concatStringsSep "\n" (mapAttrsToList sshConfig cfg.remoteNodes)} + + ${cfg.extraSSHConfig} + ''} ${config.users.users."uucp".home}/.ssh/config + + mkdir -p ${cfg.sshKeyDir} + chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${cfg.sshKeyDir} + chmod 700 ${cfg.sshKeyDir} + + ${concatStringsSep "\n" (mapAttrsToList sshKeyGen cfg.remoteNodes)} + ''; + + system.activationScripts."uucp-logs" = '' + touch ${cfg.logFile} + chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${cfg.logFile} + chmod 644 ${cfg.logFile} + touch ${cfg.statFile} + chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${cfg.statFile} + chmod 644 ${cfg.statFile} + touch ${cfg.debugFile} + chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${cfg.debugFile} + chmod 644 ${cfg.debugFile} + ''; + + environment.etc."uucp/port" = { + text = '' + port ssh + type stdin + protocol ${cfg.incomingProtocols} + '' + concatStringsSep "\n" (mapAttrsToList portSpec cfg.remoteNodes); + }; + environment.etc."uucp/sys" = { + text = cfg.extraSys + "\n" + concatStringsSep "\n" (mapAttrsToList sysSpec cfg.remoteNodes); + }; + + security.wrappers = let + wrapper = p: { + name = p; + value = { + source = "${pkgs.uucp}/bin/${p}"; + owner = "root"; + group = "root"; + setuid = true; + setgid = false; + }; + }; + in listToAttrs (map wrapper ["uucico" "cu" "uucp" "uuname" "uustat" "uux" "uuxqt"]); + + nixpkgs.overlays = [(self: super: { + uucp = super.stdenv.lib.overrideDerivation super.uucp (oldAttrs: { + configureFlags = "--with-newconfigdir=/etc/uucp"; + patches = [ + (super.writeText "mailprogram" '' + policy.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + diff --git a/policy.h b/policy.h + index 5afe34b..8e92c8b 100644 + --- a/policy.h + +++ b/policy.h + @@ -240,7 +240,7 @@ + the sendmail choice below. Otherwise, select one of the other + choices as appropriate. */ + #if 1 + -#define MAIL_PROGRAM "/usr/lib/sendmail -t" + +#define MAIL_PROGRAM "${config.security.wrapperDir}/sendmail -t" + /* #define MAIL_PROGRAM "/usr/sbin/sendmail -t" */ + #define MAIL_PROGRAM_TO_BODY 1 + #define MAIL_PROGRAM_SUBJECT_BODY 1 + '') + ]; + }); + rmail = super.writeScriptBin "rmail" '' + #!${super.stdenv.shell} + + # Dummy UUCP rmail command for postfix/qmail systems + + IFS=" " read junk from junk junk junk junk junk junk junk relay + + case "$from" in + *[@!]*) ;; + *) from="$from@$relay";; + esac + + exec ${config.security.wrapperDir}/sendmail -G -i -f "$from" -- "$@" + ''; + })]; + + environment.systemPackages = with pkgs; [ + uucp + ]; + + systemd.services."uucico@" = { + serviceConfig = { + User = "uucp"; + Type = "oneshot"; + ExecStart = "${config.security.wrapperDir}/uucico -D -S %i"; + }; + }; + + systemd.timers."uucico@" = { + timerConfig.OnActiveSec = cfg.interval; + timerConfig.OnUnitActiveSec = cfg.interval; + }; + + systemd.targets."multi-user" = { + wants = mapAttrsToList (name: node: "uucico@${name}.timer") cfg.remoteNodes; + }; + + systemd.kill-user.enable = true; + systemd.targets."sleep" = { + after = [ "kill-user@uucp.service" ]; + wants = [ "kill-user@uucp.service" ]; + }; + + networking.networkmanager.dispatcherScripts = optional cfg.nmDispatch { + type = "basic"; + source = pkgs.writeScript "callRemotes.sh" '' + #!${pkgs.stdenv.shell} + + shopt -s extglob + + case "''${2}" in + (?(vpn-)up) + ${concatStringsSep "\n " (mapAttrsToList (name: node: "${pkgs.systemd}/bin/systemctl start uucico@${name}.service") cfg.remoteNodes)} + ;; + esac + ''; + }; + }; +} -- cgit v1.2.3