1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.atd; 8 9 inherit (pkgs) at; 10 11in 12 13{ 14 15 ###### interface 16 17 options = { 18 19 services.atd.enable = mkOption { 20 type = types.bool; 21 default = false; 22 description = '' 23 Whether to enable the <command>at</command> daemon, a command scheduler. 24 ''; 25 }; 26 27 services.atd.allowEveryone = mkOption { 28 type = types.bool; 29 default = false; 30 description = '' 31 Whether to make <filename>/var/spool/at{jobs,spool}</filename> 32 writeable by everyone (and sticky). This is normally not 33 needed since the <command>at</command> commands are 34 setuid/setgid <literal>atd</literal>. 35 ''; 36 }; 37 38 }; 39 40 41 ###### implementation 42 43 config = mkIf cfg.enable { 44 45 # Not wrapping "batch" because it's a shell script (kernel drops perms 46 # anyway) and it's patched to invoke the "at" setuid wrapper. 47 security.wrappers = builtins.listToAttrs ( 48 map (program: { name = "${program}"; value = { 49 source = "${at}/bin/${program}"; 50 owner = "atd"; 51 group = "atd"; 52 setuid = true; 53 setgid = true; 54 };}) [ "at" "atq" "atrm" ]); 55 56 environment.systemPackages = [ at ]; 57 58 security.pam.services.atd = {}; 59 60 users.users = singleton 61 { name = "atd"; 62 uid = config.ids.uids.atd; 63 description = "atd user"; 64 home = "/var/empty"; 65 }; 66 67 users.groups = singleton 68 { name = "atd"; 69 gid = config.ids.gids.atd; 70 }; 71 72 systemd.services.atd = { 73 description = "Job Execution Daemon (atd)"; 74 after = [ "systemd-udev-settle.service" ]; 75 wants = [ "systemd-udev-settle.service" ]; 76 wantedBy = [ "multi-user.target" ]; 77 78 path = [ at ]; 79 80 preStart = '' 81 # Snippets taken and adapted from the original `install' rule of 82 # the makefile. 83 84 # We assume these values are those actually used in Nixpkgs for 85 # `at'. 86 spooldir=/var/spool/atspool 87 jobdir=/var/spool/atjobs 88 etcdir=/etc/at 89 90 for dir in "$spooldir" "$jobdir" "$etcdir"; do 91 if [ ! -d "$dir" ]; then 92 mkdir -p "$dir" 93 chown atd:atd "$dir" 94 fi 95 done 96 chmod 1770 "$spooldir" "$jobdir" 97 ${if cfg.allowEveryone then ''chmod a+rwxt "$spooldir" "$jobdir" '' else ""} 98 if [ ! -f "$etcdir"/at.deny ]; then 99 touch "$etcdir"/at.deny 100 chown root:atd "$etcdir"/at.deny 101 chmod 640 "$etcdir"/at.deny 102 fi 103 if [ ! -f "$jobdir"/.SEQ ]; then 104 touch "$jobdir"/.SEQ 105 chown atd:atd "$jobdir"/.SEQ 106 chmod 600 "$jobdir"/.SEQ 107 fi 108 ''; 109 110 script = "atd"; 111 112 serviceConfig.Type = "forking"; 113 }; 114 }; 115}