{ config, lib, pkgs, ... }: with lib; let portSpec = name: '' port ${name} type pipe protocol ${if builtins.hasAttr name config.services.uucp.protocols then config.services.uucp.protocols."${name}" else config.services.uucp.defaultProtocol} reliable true command ${pkgs.openssh}/bin/ssh -x -o batchmode=yes ${name} ''; sysSpec = name: '' system ${name} time Any port ${name} chat "" protocol ${if builtins.hasAttr name config.services.uucp.protocols then config.services.uucp.protocols."${name}" else config.services.uucp.defaultProtocol} command-path ${concatStringsSep " " config.services.uucp.commandPath} commands ${concatStringsSep " " (if builtins.hasAttr name config.services.uucp.commands then config.services.uucp.commands."${name}" else config.services.uucp.defaultCommands)} ''; 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"; }; sshConfig = mkOption { type = types.str; default = ""; description = "~uucp/.ssh/config"; }; remoteNodes = mkOption { type = types.listOf types.str; 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.string; default = ["rmail"]; description = "Commands allowed for remotes without explicit override"; }; commands = mkOption { type = types.attrsOf (types.listOf types.string); default = {}; description = "Override commands for specific remotes"; }; defaultProtocol = mkOption { type = types.string; default = "e"; description = "UUCP protocol to use within ssh unless overriden"; }; protocols = mkOption { type = types.attrsOf types.string; default = {}; description = "UUCP protocols to use for specific remotes"; }; 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 = "00 * * * *"; description = '' Specification of when to run `uucico' in format used by cron The default is to do so every hour ''; }; extraConfig = mkOption { type = types.string; default = '' run-uuxqt 1 ''; description = "Extra configuration to append verbatim to `/etc/uucp/config'"; }; extraSys = mkOption { type = types.string; default = '' protocol-parameter g packet-size 4096 ''; description = "Extra configuration to prepend verbatim to `/etc/uucp/sys`"; }; }; }; config = mkIf config.services.uucp.enable { environment.etc."uucp/config" = { text = '' hostname ${config.services.uucp.nodeName} spool ${config.services.uucp.spoolDir} lockdir ${config.services.uucp.lockDir} pubdir ${config.services.uucp.pubDir} logfile ${config.services.uucp.logFile} statfile ${config.services.uucp.statFile} debugfile ${config.services.uucp.debugFile} ${config.services.uucp.extraConfig} ''; }; users.users."uucp" = { name = "uucp"; isSystemUser = true; isNormalUser = false; createHome = true; home = config.services.uucp.spoolDir; description = "User for uucp over ssh"; useDefaultShell = true; } // config.services.uucp.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" config.services.uucp.sshConfig} ${config.users.users."uucp".home}/.ssh/config ''; system.activationScripts."uucp-logs" = '' touch ${config.services.uucp.logFile} chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${config.services.uucp.logFile} chmod 644 ${config.services.uucp.logFile} touch ${config.services.uucp.statFile} chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${config.services.uucp.statFile} chmod 644 ${config.services.uucp.statFile} touch ${config.services.uucp.debugFile} chown ${config.users.users."uucp".name}:${config.users.users."uucp".group} ${config.services.uucp.debugFile} chmod 644 ${config.services.uucp.debugFile} ''; environment.etc."uucp/port" = { text = '' port ssh type stdin protocol e '' + concatStringsSep "\n" (map portSpec config.services.uucp.remoteNodes); }; environment.etc."uucp/sys" = { text = config.services.uucp.extraSys + "\n" + concatStringsSep "\n" (map sysSpec config.services.uucp.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" "uuxqt" "cu" "uucp" "uuname" "uustat" "uux"]); nixpkgs.config.packageOverrides = pkgs: with pkgs; { uucp = stdenv.lib.overrideDerivation uucp (oldAttrs: { configureFlags = "--with-newconfigdir=/etc/uucp"; patches = [ (pkgs.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 "/var/setuid-wrappers/sendmail -t" /* #define MAIL_PROGRAM "/usr/sbin/sendmail -t" */ #define MAIL_PROGRAM_TO_BODY 1 #define MAIL_PROGRAM_SUBJECT_BODY 1 '') ]; }); rmail = pkgs.writeScriptBin "rmail" '' #!${pkgs.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 /var/setuid-wrappers/sendmail -G -i -f "$from" -- "$@" ''; }; environment.systemPackages = with pkgs; [ uucp ]; services.cron.systemCronJobs = (map (name: "${config.services.uucp.interval} /var/setuid-wrappers/uucico -D -S ${name}") (if (config.services.uucp.interval != null) then config.services.uucp.remoteNodes else [])); }; }