Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print: Find alternative to PPD #2088

Open
deeplow opened this issue Jul 8, 2024 · 16 comments · May be fixed by #2332
Open

Print: Find alternative to PPD #2088

deeplow opened this issue Jul 8, 2024 · 16 comments · May be fixed by #2332
Assignees
Labels
Milestone

Comments

@deeplow
Copy link
Contributor

deeplow commented Jul 8, 2024

Description

The workstation's print workflow relies on PPD files, which according to the CUPS's lpadmin manpage:

The following lpadmin options are deprecated:

-i filename

  • This option historically has been used to provide either a System V interface script or (as an implementation side-effect) a PPD file. Note: Interface scripts are not supported by CUPS. PPD files and printer drivers are deprecated and will not be supported in a future version of CUPS.

-P ppd-file

  • Specifies a PostScript Printer Description (PPD) file to use with the printer. Note: PPD files and printer drivers are deprecated and will not be supported in a future version of CUPS.

update: found the respective CUPS issue about the removal of PPD OpenPrinting/cups-sharing#4

This is also warned when running _setup_printer(). Running the same line manually on my system succeeds but shows the following on stderr:

lpadmin: Printer drivers are deprecated and will stop working in a future version of CUPS.

Steps to Reproduce

Not relevant,

Expected Behavior

Use of supported system.

Actual Behavior

Warning about using something that may not be supported in the future.

Comments

@legoktm
Copy link
Member

legoktm commented Jul 8, 2024

Related: https://github.com/freedomofpress/securedrop-engineering/issues/71 and #2156.

@deeplow
Copy link
Contributor Author

deeplow commented Jul 8, 2024

This is also warned when running _setup_printer(). Running the same line manually on my system succeeds but shows the following on stderr:

lpadmin: Printer drivers are deprecated and will stop working in a future version of CUPS.

I have confirmed now that this line also appears on the sd-device's logs.

@rocodes
Copy link
Contributor

rocodes commented Jul 8, 2024

We have sadly known about this for a while and even tried to suppress those warnings: 9bcd76a Another good reason to move away from this approach and towards the modern age :)

@legoktm legoktm added this to the 0.15.0 milestone Aug 7, 2024
@deeplow
Copy link
Contributor Author

deeplow commented Aug 26, 2024

I looked a bit into this yesterday. I was able to successfully set up an HP printer without drivers (IPP).

How I got it working

  1. Created debian-12-based a standalone qube (to make testing easier)
  2. Add qubes services: avahi and cups
  3. Start the qube and connect the printer's USB to it
  4. sudo apt install ipp-usb cups
  5. system-config-printer, just add the printer, selecting the "Generic" driver and then "IPP Everywhere". (note, the printer showed up in two places: close to the top of the list and then also under Network printers. In my case, both worked)

That was it. In the final version we may want to automate some of the steps using lp commands, but for now I'd say this already provides satisfactory results.

Research on driverless printing

I found the Debian wiki a very valuable resource. Many of my findings come from there.

How to detect if a printer supports IPP?

Run lsusb -v | grep -A 3 bInterfaceClass.*7

Then check for a value of 4 for bInterfaceProtocol indicates a USB IPP device:

  bInterfaceClass 7 Printer
  bInterfaceSubClass 1 Printer  
  bInterfaceProtocol 4  
  iInterface 0  

The interface is usually referred to as being a 7/1/4 one.

@deeplow
Copy link
Contributor Author

deeplow commented Aug 29, 2024

@rocodes and I have both had successful experiences with setting up driverless printers. The Debian wiki provides a lot of detail on the topic and it was my main resource to get things working. However, none of us managed to fully automate the process (yet).

@deeplow
Copy link
Contributor Author

deeplow commented Oct 14, 2024

Driverless Printing FAQ

Here are some answers to some of driverless printing

Driverless printing vs IPP Everywhere vs. AirPrint

IPP Everywhere == AirPrint == IPP Driverless (they are all the same thing)

Classic drivers + filters are the previous default (called Classic drivers).
The driver converts a default format to the printer's specific language.

What does driverless actually mean?

A good explanation is provided here. But the just of it is: The driver is generated on demand depending on the features the printer states are available.

How much time do we have to implement this?

CUPS 3.0 is technically not going to support PPD files. All 3.0 com components are planned to be available in mid-2025. Distro availability may be another while (especially because we rely on Debian). And technically classic drivers (PPD files) will still be available through a "printer application" and all open PPD drivers have been already ported.

What is the printer compatibility like?

Apple maintains a list of compatible printers here. I got the impression that Open Printing also has a list for driverless printers, but I could only find the one for classic drivers.

⚠️ But there's a catch! We want printers with USB support. There is no official list of printers which support IPP-over-USB, some may even not mention it but actually support it. Some even go as far as presenting as having a "WiFi only" sticker over the USB port. All one needs to to remove the sticker and connect.

As a general rule, all support modern HP printers support IPP over USB but the general exception are HP LaserJet printers (this are still from the Samsung printer division that HP bought -- ). For example, HP LaserJet Pro MFP 4101fdn is advertised as "Ethernet / USB only", but is NOT on the AirPrint compatibility list. However, it is supported through classic drivers (via hplip) so it may still support "driverless" printing via backwards compatibility? 🤔

And as the market moves more towards driverless WiFi-based printing, it is likely that the non-networked will become more scarce. Hopefully the market for security is still enough to sustain some non-networked options.

@deeplow
Copy link
Contributor Author

deeplow commented Oct 25, 2024

Following a team meeting, here are some of the conclusions:

  • general consensus with going ahead with driverless printing
  • current stance: wifi-disabled is good enough. This makes it easier to procure printers and we can suggest that it's newsroom's responsibility to investigate if it fits their threat model and implement mitigations
  • idea: we could surface to the user a warning message if the printer does have WiFi to take the appropriate mitigations. But there wasn't consensus on this point.
  • approach: we have a couple we test with (as we're doing already) if you're going beyond these, look at X list.
  • the printer recommendations should be delegated to its own discussion as we revisit Qubes hardware recommendations

@deeplow deeplow self-assigned this Nov 27, 2024
@deeplow
Copy link
Contributor Author

deeplow commented Nov 28, 2024

(Proposal) Mitigating some printer-related risks

We want to add support for driverless printing (IPP) to the workstation. However, recent vulnerabilities
in CUPS
(linux printing) highlighted just how brittle these tools can be security-wise.

Even though the SecureDrop Workstation does assume that plugged in USBs are not malicious, it could be good
to mitigate the risk of a rogue USB stick pretending to be a printer and getting to an RCE.

We can't fully mitigate this risk and are looking for Qubes 4.3 for further device control. However, for the time
being a practical mitigation involves separating the process of "adding a printer" from the "using a printer. The
vulnerabilities highlighted that the risks were mostly during the custom PPD driver generation, which takes place during
the first phase.

This has some usability implications, though. Without this mitigation, the user can just plug in any printer and so
long as the printer is IPP-compatible, it will show up in the document print dialog. With this mitigation, the administrator
will first need to add the printer and then regular users can print to it. However, because it is just a one time process,
it feels like an acceptable usability tradeoff.

Proposal downsides: this doesn't come without its downsides. If the printer were to be malicious, it could use the one-time autodetection and any 0day PPD-related RCE vectors to add a permanent RCE in sd-devices.

Investigation

Printer configs were not remaining after sd-devices-dvm restart. This means that those files are
not stored in the user's home and thus, we need them to be kept via bind-dirs

After looking at the files touched by system-config-printer dialog, I have figured out that the following are the key files to preserve:

  • "/etc/cups/ppd/*" - ppd files for added printers (even IPP printers)
  • "/etc/cups/printers.conf"

This means that adding /etc/cups to bind-dirs should suffice to keep printer configurations accross reboots. Lo and behold, it worked.

Implementation

General strategy:

  • printers are added in sd-devices-dvm (which runs avahi + cups)
  • printer settings are stored in sd-devices-dvm thanks to bind-dirs on /etc/cups
  • the user will be able to use system-config-printer ("print settings") on sd-devices-dvm to add their printer.
  • sd-devices remains with only the CUPS, thus not exposing sd-devices with the risky avahi service

How it would work in practice:

  1. open "print settings" in sd-devices-dvm
  2. attach printer to sd-devices-dvm
  3. "+ add" printer and choose the IPP network-detected one
  4. print test page
  5. shut down sd-devices-dvm
  6. restart sd-devices (if needed)

Implementation notes:

  1. setting up bind-dirs in sd-devices-dvm:
mkdir /rw/config/bind-dirs.d
echo "binds+=( '/etc/cups/' ) | sudo tee /rw/config/bind-dirs.d/30_cups.conf
  1. shut down sd-devices-dvm
  2. Add avahi to the qubes-services of sd-devices-dvm (but NOT sd-devices)

Useful commands / tricks

  • setup a local IPP server
    Add network to your sd-devices-dvm temporarily
    sudo apt install pipx
    pipx install ippserver
    ippserver --port 9100 save --pdf /tmp/
  • check which files the syste-config-printer command uses, in order to save printer settings
    sudo strace -f -t -e trace=file -p <PORT> 2>&1 | grep -p "\"/.*" | grep -v ENOENT
  • install cups-pdf in the template so that you can create a PDF printer to test things
    • PDFs by default will show up in /var/spool/cups-pdf/user/

@rocodes
Copy link
Contributor

rocodes commented Nov 28, 2024

Hey @deeplow, thanks for preparing this. My opinion (recapping from standup for the rest of the team) is a couple things:

  • I prefer to keep the dvm template free of persistent configurations, to preserve its clean template status,
  • I also think it's good to keep the user experience as straightforward as possible
  • AIUI we're still talking about a user physically plugging a device into their SDW machine. I think that it's not on us to try to mitigate what happens when they do that (more than we do with the plugging into untrusted, non-networked dispvm, anyway); I think it's a reasonable user responsibility not to plug in malicious/unknown devices.

@deeplow
Copy link
Contributor Author

deeplow commented Nov 29, 2024

That makes sense. Given the (understandable) skepticism, let's proceed with driverless printing with complete printer autodetetion.

@deeplow
Copy link
Contributor Author

deeplow commented Nov 29, 2024

Given that we have a decision on how to proceed, I'm moving forward with the implementation already. But I an implementation question.

We currently support two printers (I think). It's a bit unclear exactly which ones these are (#2087), but looking at the code, it looks like the "br7030" (aka Brother DCP-7030, I think), does NOT support AirPrint.

So much of the code is dependent on loading up manual drivers that it would just be cleaner to scrap all that and just do driverless printing directly, which translates to no code at all. We can do that, but we'd a component which retrofits printers into the IPP world. This can happen for legacy HP printers and legacy Brother printers and this would open up the possibility to have a lot of relatively old hardware also supported (might be easier to procure non-wireless models).

The downside of this is that both "printer applications" are only available as snaps and as far as I can tell, they haven't been packaged for Debian. They appear to be pretty trivial C applications, but I don't know if we want to venture into packaging other's code.

So my question is: how do we proceed:

  • Option A) we keep legacy printer (hard)code and add IPP support as well
  • Option B) we support only driverless printing and break compatibility for old printers (which we have recommended in the past)
  • Option C) we support only driverless printing but package the necessary printer applications so that legacy devices (much more than we currently support)

Personally I'm inclined for Option A just because it's not that much extra work to get around the code and we don't upset anyone's workflows. Even though I think Option C would be ideal if the respective printer applications were available out of the box in Debian. We would not only be adding support for driverless printing, while also (1) simplifying the print code a lot and (2) adding support for so many more legacy printers.

@rocodes
Copy link
Contributor

rocodes commented Nov 29, 2024

Yeah I'm with you, I would say A or B, (and if A, that we make a plan to do B and drop all the ppd driver stuff in a followup release). We have a small number of pilot users and can reach out individually to find out if anyone is still using an older printer. (I have started reaching out already to speed things along.)

It looks like to me, you would primarily be making changes to _check_printer_setup and its helper functions. So I'd lean towards making that existing setup method a self contained setup_legacy fallback option if no driverless detection works, and that way we can choose to either keep or deprecate it down the line.

@cfm
Copy link
Member

cfm commented Dec 2, 2024

Thanks for writing this up, @deeplow. Strictly speaking I think the opportunity for option B was the breaking v1.0.0 release. For a non-breaking v1.y.0 that leaves us options A or C, and I hear your concerns about the packaging implications of C. So another vote for A.

@deeplow
Copy link
Contributor Author

deeplow commented Dec 2, 2024

While implementing this I'm running into an issue where the ipp info is sometimes being shown on lpinfo -v and other times not. It seems to be inconsistent and is really messing up with the printer mechanism (which does various calls and assumes nothing has changed from the preflight to the print itself).

Example of this happening:
user@sd-devices:~$ sudo lpinfo -v
file cups-brf:/
network https
network socket
network ipp
network beh
network lpd
network http
network ipps
direct usb://HP/OfficeJet%20Pro%208120e%20series?serial=XXXXXXXX&interface=1
user@sd-devices:~$ sudo lpinfo -v
file cups-brf:/
network lpd
network beh
network http
network socket
network https
network ipps
network ipp
direct usb://HP/OfficeJet%20Pro%208120e%20series?serial=XXXXXXX&interface=1
network ipp://HP%20OfficeJet%20Pro%208120e%20series(USB)._ipp._tcp.local/

One command was run right after the other and yet in the second one it shows ipp://.

First we have to confirm that this is a problem that goes beyond my setup. Then if this is indeed a bigger issue we have several ways to approach this:

  • Find the source of the problem and fix it (if possible, or at least reduce the impact)
  • Try to get around this by running lpinfo -v several times (not ideal)
  • When a new printer is detected, it creates a new print queue (sdw-printer) instead of doing that just when it's about to print
  • Revisit the option of going with option B (dropping legacy printing all together) and just letting the print dialog handle print discovery) -- I hear your concerns @cfm
    • NOTE: If we went this route, it would opened up the path for extra debugging possibilities: the users uplugging and replugging the printer while on the print dialog to see if the printer actually gets detected.

🙋‍♂️ Ask: if someone has an IPP-capable printer, could you run lpinfo -v serveral times and see if the results differ


Investigating inconsistent results in lpinfo -v for IPP printers

I went with investigation route 1. a bit already and was investigating if ipp-usb was the culprit:

  1. I stopped the ipp-usb service with sudo system stop ipp-usb
  2. sudo ipp-usb debug
  3. In other tab run lpinfo -v and see if there when the device is not detected if the ipp-usb command ran previously shows any errors or exits (spoiler: it didn't)
  4. Repeat the above step but monitoring the output of ss -tupln to see if somehow during the non-detections the ipp server is not up (spoiler: it is always running)

Then I also opened the gnome's print dialog (via gedit) on sd-devices and it systematically listed the printer.

After this, I would say that the problem appears to be with lpinfo -v which is not properly finding IPP devices.

@rocodes
Copy link
Contributor

rocodes commented Dec 2, 2024

@deeplow: re printer detection via lpinfo: can you post the exact steps you are doing to configure the printer, either in a draft PR or a gist somewhere? I did run into this specific issue (not always reliably seeing the printer via lpinfo even after it was configured) and I left a couple notes in the driverless printing wiki page I shared a while back on different printer discovery mechanisms. (I also see that there are some discovery steps needed with lpadmin before lpinfo works, but don't want to suggest paths you have already tried.)

@deeplow
Copy link
Contributor Author

deeplow commented Dec 2, 2024

@deeplow: re printer detection via lpinfo: can you post the exact steps you are doing to configure the printer, either in a draft PR or a gist somewhere?

I added the qubes service avahi and then plugged in the printer and ran lpinfo -v. As simple as that.

I saw on your notes the command driverless list, but that didn't work for me. It just exited with no errors (but without finding the printer, which even lpinfo -v could find).

On your intructions you're creating a print queue via lpadmin. I was originally doing the same, but then I found that with driverless printing the dialog automatically shows the printers it finds. So if we do this we get two printers: sdw-printer and another one which was the printer it detected (both map to the same actually).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants