Snapping CUPS Printing Stack: Avahi support, system users/groups


cupsctl seems also to contain a hard-coded path to /etc/cups/cupsd.conf and needs patching.


Now I have CUPS under strict confinement nearly completely running.

The changes I have uploaded to GitHub as commit fa4a62d5.

Everything seems to work, except

  • Web interface does not allow admin tasks. I tried to log in with my user name and password. I have added “adm” to the SystemGroup again, and this way I can do administration without sudo or password on the command line (lpadmin, cupsctl, …) but I cannot log in for the admin page of the web interface.
  • Command line utilities cannot access file in the home directory. I have added the plug “home” to them but it still does not work. For the time being you have to print with cat <file> | cups.lp -d <printer>. Printing with cups.lp -d <printer> <file> does not work.

Here are the changes I did:

  • Patched CUPS to

    • allow root as CUPS user and group (cupsd-allow-root-as-cups-user.patch)
    • allow the system groups containing the CUPS group (cupsd-allow-group-and-systemgroup-be-the-same.patch)
    • not do setgroups() system calls (sed magic in snapcraft.yaml)
    • pass the $PATH environment variable on to programs called by CUPS (cupsd-pass-on-path.patch)
    • let its utilities access cupsd.conf only via HTTP and not via local file access (libcups-do-not-read-cupsd-conf-from-local-file.patch)

    The first three changes make CUPS able to run helper programs (filters, backends, CGI programs, …) as root and trying to set any user or group relations. Needed for printing and for making the pages of the web interface work.
    The forth makes filters and backends find helper utilities which are part of the snap (like Poppler’s pdftocairo).
    The last one makes the cupsctl utility work.

  • Set CUPS user and CUPS group to root, so that all helper programs called by CUPS run as root and so they can access all needed files which are owned by root.

  • Added “adm” group to the system groups. This is a temporary hack until we can create and use the “lpadmin” group the snap. Now the first user (also member of “adm” group can do CUPS administration tasks with lpadmin, cupsctl, …

  • Added plug “home” to the lp, lpoptions, lpadmin, and cupsfilter utilities.

  • Set maximum size for error_log to 10 MB.


Updated the file of the snap’s GIT repo.


The first of these exceptions is at least partially solved. For my testing I have always used ~/.bashrc as file to be printed, not realising that it is a hidden file. Normal files can be printed directly with cups.lp -d <printer> <file> now.


I get the admin part of the web interface working if I run

sudo chmod 711 /var/snap/cups/current/var/run/certs/
sudo chown root.root /var/snap/cups/current/var/run/certs/

after installing the snap.
To get the snap already installing with these permissions/ownerships I would need to apply these operations to the appropriate files already when building the snap, right after “make install” of CUPS. @ondra, @ogra, @jdstrand, do you know how to do this?


These directories are in the writable SNAP_DATA that your snap manages, so snapcraft won’t help you. You can create this in a number of ways: use one of the snapd hook mechanisms (eg, Install and remove hooks) or creating a wrapper around your daemon to create them if they don’t exist.


Can I run chown and chmod in the run-cupsd script? I had to weed out all the chown() and chmod() from cupsd itself to make cupsd running under confinenment.


I have tested the confined CUPS snap on Ubuntu Core now and there everything works as described here for Classic except Avahi. It seems that Avahi is not actually broadcasting into the local network, as I cannot see my printer set up on Ubuntu Core in avahi-discover on the host but I see my printer which I have set up under the snap’s CUPS on my Ubuntu Bionic VM.


Yes. chmod is always fine. chown to root:root like you said you wanted to do is also fine.


@jdstrand, tried to add

chmod 711 $SNAP_DATA/var/run/certs/
chown root.root $SNAP_DATA/var/run/certs/

to run-cupsd, right before calling the CUPS daemon and when installing the snap, cupsd does not get started as the script stops on chown:

Nov 17 16:02:03 virt-devel cups.cupsd[4385]: /snap/cups/x20/run-cupsd: 53: /snap
/cups/x20/run-cupsd: chown: Permission denied
Nov 17 16:02:03 virt-devel kernel: [17573.650149] audit: type=1400 audit(1510941723.306:1496): apparmor="DENIED" operation="exec" profile="snap.cups.cupsd" name="/bin/chown" pid=4446 comm="run-cupsd" requested_mask="x" denied_mask="x" fsuid=0 ouid=0
Nov 17 16:02:03 virt-devel systemd[1]: snap.cups.cupsd.service: Main process exited, code=exited, status=126/n/a


I have some deny messages when CUPS is trying to access PAM files (probably appeared when trying to enter admin page of CUPS web interface, I am on the Bionic VM, snap without chmod/chown in run-cupsd):

Nov 17 16:15:12 virt-devel kernel: [18362.552184] audit: type=1400 audit(1510942
512.205:1641): apparmor="DENIED" operation="open" profile="snap.cups.cupsd" name
="/etc/pam.d/cups" pid=4830 comm="cupsd" requested_mask="r" denied_mask="r" fsui
d=0 ouid=0
Nov 17 16:15:12 virt-devel kernel: [18362.552186] audit: type=1400 audit(1510942
512.205:1642): apparmor="DENIED" operation="open" profile="snap.cups.cupsd" name
="/etc/pam.d/other" pid=4830 comm="cupsd" requested_mask="r" denied_mask="r" fsu
id=0 ouid=0

How to proceed here? Do we need an interface for PAM? Or do we need to build CUPS without PAM? @jdstrand?


Update about the printing stack snap running on Ubuntu Core: Printers set up on Ubuntu Core get discovered by remote machines (so Ubuntu Core is able to broadcast DNS-SD services) but the Ubuntu Core system does not discover the shared printers of the remote machines.


We currently only allow use of most of the chown family of syscalls for chowning to root:root. fixes this to allow chown root:root <path>.


@till.kamppeter - applications (currently) don’t have access to processing logins via libpam. It is possible to add an interface for this, but it would be quite privileged in order to perform the authentication. The interface would also get potentially messy on (at least) classic since any number of pam modules might be installed on the system that might require additional accesses.

For now, compiling without pam is probably the way to go.


@jdstrand, thanks for the info. When will this feature make it into snapd?


@jdstrand, I compiled CUPS with --disable-pam now, but now I get this when trying to log into the admin page of the web interface:

Nov 17 20:11:09 virt-devel kernel: [32519.550607] audit: type=1400 audit(1510956669.146:2017): apparmor="DENIED" operation="open" profile="snap.cups.cupsd" name="/etc/shadow" pid=7272 comm="cupsd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
Nov 17 20:11:09 virt-devel kernel: [32519.550609] audit: type=1400 audit(1510956669.146:2018): apparmor="DENIED" operation="open" profile="snap.cups.cupsd" name="/var/lib/extrausers/shadow" pid=7272 comm="cupsd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0

Is there a way to make CUPS accessing these files?

#86 was merged today and will be in snapd 2.30. I don’t know when that will be released, but I think I heard early December.


@jdstrand, any thought about this? Without PAM CUPS reads the /etc/password and /var/lib/extrausers/shadow files directly, to see whether the user logged in into the web interface is in the adm group (in the future libadm, when this problem is solved). This way the web interface would work correctly.


The ‘account-control’ interface allows managing extrausers so you would get access to the extrausers shadow file, but this isn’t the right interface for what you want. The problem is that your snap is trying to authenticate users against the configured databases for the system and we don’t (currently) have interfaces that support this.

To support this we would need very clear use cases and to understand exactly what we would want to support. Your application initially wanted to authenticate against PAM which might use local databases, ldap, kerberos, winbind, etc which makes writing an authentication interface tricky. I think ideally, snapd would proxy authentication requests so that the raw files aren’t exposed to the snap. Eg, rather than giving CUPS access to /etc/shadow, CUPS asks snapd if a given user/password pair is valid. In this manner, the snap only has access to authentication credentials that the user input, and not everything on the system. I suspect this could be done via a PAM module supplied by snapd (which would have to be very carefully written). This needs design.

Before that can happen, can you precisely describe the different mechanisms that that CUPS uses to authenticate users?


I never have looked into which authentication methods CUPS supports. I have hit into this only now. At least CUPS supports PAM (what probably is used in the standard desktop .deb packages of CUPS), accessing local user/password files (probably through some library function, what it did now after compiling with --disable-pam), and also more sophisticated enterprise network methods like for example Kerberos).