at 17.09-beta 11 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 inherit (pkgs) cups cups-pk-helper cups-filters; 8 9 cfg = config.services.printing; 10 11 avahiEnabled = config.services.avahi.enable; 12 polkitEnabled = config.security.polkit.enable; 13 14 additionalBackends = pkgs.runCommand "additional-cups-backends" { } 15 '' 16 mkdir -p $out 17 if [ ! -e ${cups.out}/lib/cups/backend/smb ]; then 18 mkdir -p $out/lib/cups/backend 19 ln -sv ${pkgs.samba}/bin/smbspool $out/lib/cups/backend/smb 20 fi 21 22 # Provide support for printing via HTTPS. 23 if [ ! -e ${cups.out}/lib/cups/backend/https ]; then 24 mkdir -p $out/lib/cups/backend 25 ln -sv ${cups.out}/lib/cups/backend/ipp $out/lib/cups/backend/https 26 fi 27 ''; 28 29 # Here we can enable additional backends, filters, etc. that are not 30 # part of CUPS itself, e.g. the SMB backend is part of Samba. Since 31 # we can't update ${cups.out}/lib/cups itself, we create a symlink tree 32 # here and add the additional programs. The ServerBin directive in 33 # cupsd.conf tells cupsd to use this tree. 34 bindir = pkgs.buildEnv { 35 name = "cups-progs"; 36 paths = 37 [ cups.out additionalBackends cups-filters pkgs.ghostscript ] 38 ++ cfg.drivers; 39 pathsToLink = [ "/lib" "/share/cups" "/bin" ]; 40 postBuild = cfg.bindirCmds; 41 ignoreCollisions = true; 42 }; 43 44 writeConf = name: text: pkgs.writeTextFile { 45 inherit name text; 46 destination = "/etc/cups/${name}"; 47 }; 48 49 cupsFilesFile = writeConf "cups-files.conf" '' 50 SystemGroup root wheel 51 52 ServerBin ${bindir}/lib/cups 53 DataDir ${bindir}/share/cups 54 DocumentRoot ${cups.out}/share/doc/cups 55 56 AccessLog syslog 57 ErrorLog syslog 58 PageLog syslog 59 60 TempDir ${cfg.tempDir} 61 62 # User and group used to run external programs, including 63 # those that actually send the job to the printer. Note that 64 # Udev sets the group of printer devices to `lp', so we want 65 # these programs to run as `lp' as well. 66 User cups 67 Group lp 68 69 ${cfg.extraFilesConf} 70 ''; 71 72 cupsdFile = writeConf "cupsd.conf" '' 73 ${concatMapStrings (addr: '' 74 Listen ${addr} 75 '') cfg.listenAddresses} 76 Listen /var/run/cups/cups.sock 77 78 SetEnv PATH /var/lib/cups/path/lib/cups/filter:/var/lib/cups/path/bin 79 80 DefaultShared ${if cfg.defaultShared then "Yes" else "No"} 81 82 Browsing ${if cfg.browsing then "Yes" else "No"} 83 84 WebInterface ${if cfg.webInterface then "Yes" else "No"} 85 86 ${cfg.extraConf} 87 ''; 88 89 browsedFile = writeConf "cups-browsed.conf" cfg.browsedConf; 90 91 rootdir = pkgs.buildEnv { 92 name = "cups-progs"; 93 paths = [ 94 cupsFilesFile 95 cupsdFile 96 (writeConf "client.conf" cfg.clientConf) 97 (writeConf "snmp.conf" cfg.snmpConf) 98 ] ++ optional avahiEnabled browsedFile 99 ++ cfg.drivers; 100 pathsToLink = [ "/etc/cups" ]; 101 ignoreCollisions = true; 102 }; 103 104 filterGutenprint = pkgs: filter (pkg: pkg.meta.isGutenprint or false == true) pkgs; 105 containsGutenprint = pkgs: length (filterGutenprint pkgs) > 0; 106 getGutenprint = pkgs: head (filterGutenprint pkgs); 107 108in 109 110{ 111 112 ###### interface 113 114 options = { 115 services.printing = { 116 117 enable = mkOption { 118 type = types.bool; 119 default = false; 120 description = '' 121 Whether to enable printing support through the CUPS daemon. 122 ''; 123 }; 124 125 listenAddresses = mkOption { 126 type = types.listOf types.str; 127 default = [ "127.0.0.1:631" ]; 128 example = [ "*:631" ]; 129 description = '' 130 A list of addresses and ports on which to listen. 131 ''; 132 }; 133 134 bindirCmds = mkOption { 135 type = types.lines; 136 internal = true; 137 default = ""; 138 description = '' 139 Additional commands executed while creating the directory 140 containing the CUPS server binaries. 141 ''; 142 }; 143 144 defaultShared = mkOption { 145 type = types.bool; 146 default = false; 147 description = '' 148 Specifies whether local printers are shared by default. 149 ''; 150 }; 151 152 browsing = mkOption { 153 type = types.bool; 154 default = false; 155 description = '' 156 Specifies whether shared printers are advertised. 157 ''; 158 }; 159 160 webInterface = mkOption { 161 type = types.bool; 162 default = true; 163 description = '' 164 Specifies whether the web interface is enabled. 165 ''; 166 }; 167 168 extraFilesConf = mkOption { 169 type = types.lines; 170 default = ""; 171 description = '' 172 Extra contents of the configuration file of the CUPS daemon 173 (<filename>cups-files.conf</filename>). 174 ''; 175 }; 176 177 extraConf = mkOption { 178 type = types.lines; 179 default = ""; 180 example = 181 '' 182 BrowsePoll cups.example.com 183 LogLevel debug 184 ''; 185 description = '' 186 Extra contents of the configuration file of the CUPS daemon 187 (<filename>cupsd.conf</filename>). 188 ''; 189 }; 190 191 clientConf = mkOption { 192 type = types.lines; 193 default = ""; 194 example = 195 '' 196 ServerName server.example.com 197 Encryption Never 198 ''; 199 description = '' 200 The contents of the client configuration. 201 (<filename>client.conf</filename>) 202 ''; 203 }; 204 205 browsedConf = mkOption { 206 type = types.lines; 207 default = ""; 208 example = 209 '' 210 BrowsePoll cups.example.com 211 ''; 212 description = '' 213 The contents of the configuration. file of the CUPS Browsed daemon 214 (<filename>cups-browsed.conf</filename>) 215 ''; 216 }; 217 218 snmpConf = mkOption { 219 type = types.lines; 220 default = '' 221 Address @LOCAL 222 ''; 223 description = '' 224 The contents of <filename>/etc/cups/snmp.conf</filename>. See "man 225 cups-snmp.conf" for a complete description. 226 ''; 227 }; 228 229 drivers = mkOption { 230 type = types.listOf types.path; 231 default = []; 232 example = literalExample "[ pkgs.gutenprint pkgs.hplip pkgs.splix ]"; 233 description = '' 234 CUPS drivers to use. Drivers provided by CUPS, cups-filters, 235 Ghostscript and Samba are added unconditionally. If this list contains 236 Gutenprint (i.e. a derivation with 237 <literal>meta.isGutenprint = true</literal>) the PPD files in 238 <filename>/var/lib/cups/ppd</filename> will be updated automatically 239 to avoid errors due to incompatible versions. 240 ''; 241 }; 242 243 tempDir = mkOption { 244 type = types.path; 245 default = "/tmp"; 246 example = "/tmp/cups"; 247 description = '' 248 CUPSd temporary directory. 249 ''; 250 }; 251 }; 252 253 }; 254 255 256 ###### implementation 257 258 config = mkIf config.services.printing.enable { 259 260 users.extraUsers = singleton 261 { name = "cups"; 262 uid = config.ids.uids.cups; 263 group = "lp"; 264 description = "CUPS printing services"; 265 }; 266 267 environment.systemPackages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper; 268 environment.etc."cups".source = "/var/lib/cups"; 269 270 services.dbus.packages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper; 271 272 # Cups uses libusb to talk to printers, and does not use the 273 # linux kernel driver. If the driver is not in a black list, it 274 # gets loaded, and then cups cannot access the printers. 275 boot.blacklistedKernelModules = [ "usblp" ]; 276 277 systemd.packages = [ cups.out ]; 278 279 systemd.services.cups = 280 { wantedBy = [ "multi-user.target" ]; 281 wants = [ "network.target" ]; 282 after = [ "network.target" ]; 283 284 path = [ cups.out ]; 285 286 preStart = 287 '' 288 mkdir -m 0700 -p /var/cache/cups 289 mkdir -m 0700 -p /var/spool/cups 290 mkdir -m 0755 -p ${cfg.tempDir} 291 292 mkdir -m 0755 -p /var/lib/cups 293 # Backwards compatibility 294 if [ ! -L /etc/cups ]; then 295 mv /etc/cups/* /var/lib/cups 296 rmdir /etc/cups 297 ln -s /var/lib/cups /etc/cups 298 fi 299 # First, clean existing symlinks 300 if [ -n "$(ls /var/lib/cups)" ]; then 301 for i in /var/lib/cups/*; do 302 [ -L "$i" ] && rm "$i" 303 done 304 fi 305 # Then, populate it with static files 306 cd ${rootdir}/etc/cups 307 for i in *; do 308 [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i" 309 done 310 311 #update path reference 312 [ -L /var/lib/cups/path ] && \ 313 rm /var/lib/cups/path 314 [ ! -e /var/lib/cups/path ] && \ 315 ln -s ${bindir} /var/lib/cups/path 316 317 ${optionalString (containsGutenprint cfg.drivers) '' 318 if [ -d /var/lib/cups/ppd ]; then 319 ${getGutenprint cfg.drivers}/bin/cups-genppdupdate -p /var/lib/cups/ppd 320 fi 321 ''} 322 ''; 323 324 serviceConfig.PrivateTmp = true; 325 }; 326 327 systemd.services.cups-browsed = mkIf avahiEnabled 328 { description = "CUPS Remote Printer Discovery"; 329 330 wantedBy = [ "multi-user.target" ]; 331 wants = [ "cups.service" "avahi-daemon.service" ]; 332 bindsTo = [ "cups.service" "avahi-daemon.service" ]; 333 partOf = [ "cups.service" "avahi-daemon.service" ]; 334 after = [ "cups.service" "avahi-daemon.service" ]; 335 336 path = [ cups ]; 337 338 serviceConfig.ExecStart = "${cups-filters}/bin/cups-browsed"; 339 340 restartTriggers = [ browsedFile ]; 341 }; 342 343 services.printing.extraConf = 344 '' 345 LogLevel info 346 347 DefaultAuthType Basic 348 349 <Location /> 350 Order allow,deny 351 Allow localhost 352 </Location> 353 354 <Location /admin> 355 Order allow,deny 356 Allow localhost 357 </Location> 358 359 <Location /admin/conf> 360 AuthType Basic 361 Require user @SYSTEM 362 Order allow,deny 363 Allow localhost 364 </Location> 365 366 <Policy default> 367 <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job CUPS-Move-Job> 368 Require user @OWNER @SYSTEM 369 Order deny,allow 370 </Limit> 371 372 <Limit Pause-Printer Resume-Printer Set-Printer-Attributes Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After CUPS-Add-Printer CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default> 373 AuthType Basic 374 Require user @SYSTEM 375 Order deny,allow 376 </Limit> 377 378 <Limit Cancel-Job CUPS-Authenticate-Job> 379 Require user @OWNER @SYSTEM 380 Order deny,allow 381 </Limit> 382 383 <Limit All> 384 Order deny,allow 385 </Limit> 386 </Policy> 387 ''; 388 389 security.pam.services.cups = {}; 390 391 }; 392}