at 16.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 gutenprint; 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 ++ optional cfg.gutenprint gutenprint 39 ++ cfg.drivers; 40 pathsToLink = [ "/lib/cups" "/share/cups" "/bin" ]; 41 postBuild = cfg.bindirCmds; 42 ignoreCollisions = true; 43 }; 44 45 writeConf = name: text: pkgs.writeTextFile { 46 inherit name text; 47 destination = "/etc/cups/${name}"; 48 }; 49 50 cupsFilesFile = writeConf "cups-files.conf" '' 51 SystemGroup root wheel 52 53 ServerBin ${bindir}/lib/cups 54 DataDir ${bindir}/share/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 ${bindir}/lib/cups/filter:${bindir}/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 ++ optional cfg.gutenprint gutenprint 100 ++ cfg.drivers; 101 pathsToLink = [ "/etc/cups" ]; 102 ignoreCollisions = true; 103 }; 104 105in 106 107{ 108 109 ###### interface 110 111 options = { 112 services.printing = { 113 114 enable = mkOption { 115 type = types.bool; 116 default = false; 117 description = '' 118 Whether to enable printing support through the CUPS daemon. 119 ''; 120 }; 121 122 listenAddresses = mkOption { 123 type = types.listOf types.str; 124 default = [ "127.0.0.1:631" ]; 125 example = [ "*:631" ]; 126 description = '' 127 A list of addresses and ports on which to listen. 128 ''; 129 }; 130 131 bindirCmds = mkOption { 132 type = types.lines; 133 internal = true; 134 default = ""; 135 description = '' 136 Additional commands executed while creating the directory 137 containing the CUPS server binaries. 138 ''; 139 }; 140 141 defaultShared = mkOption { 142 type = types.bool; 143 default = false; 144 description = '' 145 Specifies whether local printers are shared by default. 146 ''; 147 }; 148 149 browsing = mkOption { 150 type = types.bool; 151 default = false; 152 description = '' 153 Specifies whether shared printers are advertised. 154 ''; 155 }; 156 157 webInterface = mkOption { 158 type = types.bool; 159 default = true; 160 description = '' 161 Specifies whether the web interface is enabled. 162 ''; 163 }; 164 165 extraFilesConf = mkOption { 166 type = types.lines; 167 default = ""; 168 description = '' 169 Extra contents of the configuration file of the CUPS daemon 170 (<filename>cups-files.conf</filename>). 171 ''; 172 }; 173 174 extraConf = mkOption { 175 type = types.lines; 176 default = ""; 177 example = 178 '' 179 BrowsePoll cups.example.com 180 LogLevel debug 181 ''; 182 description = '' 183 Extra contents of the configuration file of the CUPS daemon 184 (<filename>cupsd.conf</filename>). 185 ''; 186 }; 187 188 clientConf = mkOption { 189 type = types.lines; 190 default = ""; 191 example = 192 '' 193 ServerName server.example.com 194 Encryption Never 195 ''; 196 description = '' 197 The contents of the client configuration. 198 (<filename>client.conf</filename>) 199 ''; 200 }; 201 202 browsedConf = mkOption { 203 type = types.lines; 204 default = ""; 205 example = 206 '' 207 BrowsePoll cups.example.com 208 ''; 209 description = '' 210 The contents of the configuration. file of the CUPS Browsed daemon 211 (<filename>cups-browsed.conf</filename>) 212 ''; 213 }; 214 215 snmpConf = mkOption { 216 type = types.lines; 217 default = '' 218 Address @LOCAL 219 ''; 220 description = '' 221 The contents of <filename>/etc/cups/snmp.conf</filename>. See "man 222 cups-snmp.conf" for a complete description. 223 ''; 224 }; 225 226 gutenprint = mkOption { 227 type = types.bool; 228 default = false; 229 description = '' 230 Whether to enable Gutenprint drivers for CUPS. This includes auto-updating 231 Gutenprint PPD files. 232 ''; 233 }; 234 235 drivers = mkOption { 236 type = types.listOf types.path; 237 default = []; 238 example = literalExample "[ pkgs.splix ]"; 239 description = '' 240 CUPS drivers to use. Drivers provided by CUPS, cups-filters, Ghostscript 241 and Samba are added unconditionally. For adding Gutenprint, see 242 <literal>gutenprint</literal>. 243 ''; 244 }; 245 246 tempDir = mkOption { 247 type = types.path; 248 default = "/tmp"; 249 example = "/tmp/cups"; 250 description = '' 251 CUPSd temporary directory. 252 ''; 253 }; 254 }; 255 256 }; 257 258 259 ###### implementation 260 261 config = mkIf config.services.printing.enable { 262 263 users.extraUsers = singleton 264 { name = "cups"; 265 uid = config.ids.uids.cups; 266 group = "lp"; 267 description = "CUPS printing services"; 268 }; 269 270 environment.systemPackages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper; 271 environment.etc."cups".source = "/var/lib/cups"; 272 273 services.dbus.packages = [ cups.out ] ++ optional polkitEnabled cups-pk-helper; 274 275 # Cups uses libusb to talk to printers, and does not use the 276 # linux kernel driver. If the driver is not in a black list, it 277 # gets loaded, and then cups cannot access the printers. 278 boot.blacklistedKernelModules = [ "usblp" ]; 279 280 systemd.packages = [ cups.out ]; 281 282 systemd.services.cups = 283 { wantedBy = [ "multi-user.target" ]; 284 wants = [ "network.target" ]; 285 after = [ "network.target" ]; 286 287 path = [ cups.out ]; 288 289 preStart = 290 '' 291 mkdir -m 0700 -p /var/cache/cups 292 mkdir -m 0700 -p /var/spool/cups 293 mkdir -m 0755 -p ${cfg.tempDir} 294 295 mkdir -m 0755 -p /var/lib/cups 296 # Backwards compatibility 297 if [ ! -L /etc/cups ]; then 298 mv /etc/cups/* /var/lib/cups 299 rmdir /etc/cups 300 ln -s /var/lib/cups /etc/cups 301 fi 302 # First, clean existing symlinks 303 if [ -n "$(ls /var/lib/cups)" ]; then 304 for i in /var/lib/cups/*; do 305 [ -L "$i" ] && rm "$i" 306 done 307 fi 308 # Then, populate it with static files 309 cd ${rootdir}/etc/cups 310 for i in *; do 311 [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i" 312 done 313 ${optionalString cfg.gutenprint '' 314 if [ -d /var/lib/cups/ppd ]; then 315 ${gutenprint}/bin/cups-genppdupdate -p /var/lib/cups/ppd 316 fi 317 ''} 318 ''; 319 }; 320 321 systemd.services.cups-browsed = mkIf avahiEnabled 322 { description = "CUPS Remote Printer Discovery"; 323 324 wantedBy = [ "multi-user.target" ]; 325 wants = [ "cups.service" "avahi-daemon.service" ]; 326 bindsTo = [ "cups.service" "avahi-daemon.service" ]; 327 partOf = [ "cups.service" "avahi-daemon.service" ]; 328 after = [ "cups.service" "avahi-daemon.service" ]; 329 330 path = [ cups ]; 331 332 serviceConfig.ExecStart = "${cups-filters}/bin/cups-browsed"; 333 334 restartTriggers = [ browsedFile ]; 335 }; 336 337 services.printing.extraConf = 338 '' 339 LogLevel info 340 341 DefaultAuthType Basic 342 343 <Location /> 344 Order allow,deny 345 Allow localhost 346 </Location> 347 348 <Location /admin> 349 Order allow,deny 350 Allow localhost 351 </Location> 352 353 <Location /admin/conf> 354 AuthType Basic 355 Require user @SYSTEM 356 Order allow,deny 357 Allow localhost 358 </Location> 359 360 <Policy default> 361 <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> 362 Require user @OWNER @SYSTEM 363 Order deny,allow 364 </Limit> 365 366 <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> 367 AuthType Basic 368 Require user @SYSTEM 369 Order deny,allow 370 </Limit> 371 372 <Limit Cancel-Job CUPS-Authenticate-Job> 373 Require user @OWNER @SYSTEM 374 Order deny,allow 375 </Limit> 376 377 <Limit All> 378 Order deny,allow 379 </Limit> 380 </Policy> 381 ''; 382 383 security.pam.services.cups = {}; 384 385 }; 386}