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

After running

sudo snap connect cups:avahi-control

and rebooting the virtual machine the auto discovery of the shared printers works again, in both directions. So after manually connecting Avahi the CUPS/Avahi/D-Bus/cups-browsed realm seems to fully work with a confined snap.

Can I reach the same goal also without rebooting the VM? How do I restart daemons within a snap?

We also need a way to connect the Avahi interface automatically.

For CUPS <-> Avahi and cups-browsed <-> Avahi communication only the D-Bus within the snap’s confinement (and perhaps also through the avahi-control interface) is needed, and so Avahi use seems to work without D-Bus denials.
The denials are perhaps from notification which CUPS sends out to tell about events as queue or job creation, job finishing, … These being denied should not prevent CUPS from working, but there will be no printing-related desktop notifications.

@jdstrand ignore this comment please. Clearly it was long day for me and I forgot to connect avahi interface, so it was legitimate denial.

Did some first tests:

  • cups.lp <file> does not work, one has to use cat <file> | cups.lp. lp would need access to home directory.
  • Administrative operations, like cups.cancel -a need sudo. No privileged user or group for administration.
  • sudo cups.cupsctl tries to access /etc/cups/cupsd.conf instead of the one of the snap. Is actually the cupsctl executable of the snap executed here? Or the one of the system?
  • Printing does not work, filters and backends stop with ... stopped with status 101 (Operation not permitted). Filters/backends need to be investigated.
  • Web interface on http://localhost:10631 can get accessed with browser running on the VM, but any of its pages (admin, printers, classes, …) gives an “Internal Server Error”.

I know you moved on from snapcraft-preload, but I suspect you are missing a build or stage packages. @sergiusens or @Trevinho, can you look at this, perhaps updating any relevant documentation?

Make a request for auto-connection following Process for aliases, auto-connections and tracks

The stopped with status 101 (Operation not permitted) problem of the filters is probably caused by the fact that CUPS runs these as the user “lp” which actually exists in the system (at least in the classic one) but as we have patched out all chown/chmod operations all job files in the spool area are owned by user root and group root and being only group-readable and not world-readable the filters cannot access the job data.
CUPS needs to be patched so that the “lp” user and group is actually root (ID = 0).

The CGI programs of the web interface also need to be checked whether CUPS runs them as root and not as an unprivileged system user.

CUPS internally sets the the PATH environment variable to <CUPS filter dir>:/bin:/sbin:/bin:/usr/bin, we need it to take the PATH variable of its environment and add the filter dir to that, patch is probably similar to the one which we already apply for LD_LIBRARY_PATH. This is needed for filters to find helper utilities.

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 README.md 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?