diff --git a/salt/sys-print/README.md b/salt/sys-print/README.md new file mode 100644 index 00000000..b9015526 --- /dev/null +++ b/salt/sys-print/README.md @@ -0,0 +1,114 @@ +# sys-print + +Printer environment in Qubes OS. + +## Table of Contents + +* [Description](#description) +* [Security](#security) +* [Installation](#installation) +* [Access Control](#access-control) +* [Usage](#usage) + * [Add a printer](#add-a-printer) + * [Print](#print) +* [Credits](#credits) + +## Description + +Creates a print server named "sys-print" and a named disposable +"disp-sys-print" qube for sending files to your configured printer, which can +be done over the network or with IPP-over-USB. + +## Security + +The client does not have CUPS, does not need internet connection and does not +have USB devices connected. + +Using CUPS in a dedicated qube reduces attack surface and has a better +usability as you only need to configure the printer in one qube and other +qubes will have access through Qrexec. + +If the devices connected to the server qube can attack the CUPS server, it can +escalate the attack to the client qube. Usage of disposables servers does not +prevent this from happening, it just avoids persistent infection on the +server, where you could attribute different printers to different levels of +trust. + +Sending files to the print server with `qvm-copy` is always safer than +allowing a direct connection from the qube that wants to print files to the +qube that has access to the printer. + +## Installation + +- Top: +```sh +sudo qubesctl top.enable sys-print +sudo qubesctl --targets=tpl-sys-print,sys-print state.apply +sudo qubesctl top.disable sys-print +sudo qubesctl state.apply sys-print.appmenus +``` + +- State: + +```sh +sudo qubesctl state.apply sys-print.create +sudo qubesctl --skip-dom0 --targets=tpl-sys-print state.apply sys-print.install +sudo qubesctl --skip-dom0 --targets=dvm-sys-print,sys-print state.apply sys-print.configure +sudo qubesctl state.apply sys-print.appmenus +``` + + +If you want to install all printer drivers: +```sh +sudo qubesctl --skip-dom0 --targets=tpl-sys-print state.apply sys-print.install-driver-all +``` + +On the client template: +```sh +sudo qubesctl --skip-dom0 --targets=tpl-QUBE -print state.apply sys-print.install-client +``` + +The client qube requires the split Print service to be enabled: +```sh +qvm-features QUBE service.print-setup 1 +``` + +## Access Control + +_Default policy_: `ask` `all` requests requesting to use the +`qusal.Print` RPC service. + +`Asking` can spawn multiple requests depending on the client, usage of `allow` +is recommended for trusted clients. + +Allow access to the specified printing agent based on the qube tag: +```qrexecpolicy +qusal.Print * @tag:print-client @default allow target=sys-print +``` + +Always recommended to end with an explicit deny rule: +```qrexecpolicy +qusal.Print * @anyvm @anyvm deny +``` + +## Usage + +### Add a printer + +You will configure your printer from `sys-print` or `disp-sys-print`, it can +connect over the network or USB. If you do not want to save printing +configuration, use `disp-sys-print`. + +On `sys-print` or `disp-sys-print`, add your printer: +```sh +system-config-printer +``` + +### Print + +On the client, select the file to print, open it with an editor, viewer or +browser and target the desired printer. + +## Credits + +- [Unman](https://github.com/unman/shaker/tree/main/sys-print) diff --git a/salt/sys-print/appmenus.sls b/salt/sys-print/appmenus.sls new file mode 100644 index 00000000..a84a2478 --- /dev/null +++ b/salt/sys-print/appmenus.sls @@ -0,0 +1,8 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% from 'utils/macros/sync-appmenus.sls' import sync_appmenus -%} +{{ sync_appmenus('tpl-' ~ sls_path) }} diff --git a/salt/sys-print/appmenus.top b/salt/sys-print/appmenus.top new file mode 100644 index 00000000..74766f4d --- /dev/null +++ b/salt/sys-print/appmenus.top @@ -0,0 +1,10 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dom0': + - match: nodegroup + - sys-print.appmenus diff --git a/salt/sys-print/clone.sls b/salt/sys-print/clone.sls new file mode 100644 index 00000000..94671869 --- /dev/null +++ b/salt/sys-print/clone.sls @@ -0,0 +1,8 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% from 'utils/macros/clone-template.sls' import clone_template -%} +{{ clone_template('debian-minimal', sls_path) }} diff --git a/salt/sys-print/clone.top b/salt/sys-print/clone.top new file mode 100644 index 00000000..022417be --- /dev/null +++ b/salt/sys-print/clone.top @@ -0,0 +1,10 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dom0': + - match: nodegroup + - sys-print.clone diff --git a/salt/sys-print/configure.sls b/salt/sys-print/configure.sls new file mode 100644 index 00000000..a88fe9fa --- /dev/null +++ b/salt/sys-print/configure.sls @@ -0,0 +1,24 @@ +{# +SPDX-FileCopyrightText: 2022 - 2023 unman +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +"{{ slsdotpath }}-bind-dirs": + file.managed: + - name: /rw/config/qubes-bind-dirs.d/50-sys-print.conf + - source: salt://{{ slsdotpath }}/files/server/qubes-bind-dirs.d/50-sys-print.conf + - mode: '0644' + - user: root + - group: root + - makedirs: True + +"{{ slsdotpath }}-rpc": + file.managed: + - name: /etc/qubes-rpc/qusal.Print + - source: salt://{{ slsdotpath }}/files/server/rpc/qusal.Print + - mode: '0755' + - user: root + - group: root + - makedirs: True diff --git a/salt/sys-print/configure.top b/salt/sys-print/configure.top new file mode 100644 index 00000000..6d3507d0 --- /dev/null +++ b/salt/sys-print/configure.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dvm-sys-print,sys-print': + - sys-print.configure diff --git a/salt/sys-print/create.sls b/salt/sys-print/create.sls new file mode 100644 index 00000000..397e4644 --- /dev/null +++ b/salt/sys-print/create.sls @@ -0,0 +1,127 @@ +{# +SPDX-FileCopyrightText: 2022 - 2023 unman +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{%- from "qvm/template.jinja" import load -%} + +include: + - .clone + +{% load_yaml as defaults -%} +name: tpl-{{ slsdotpath }} +force: True +require: +- sls: {{ slsdotpath }}.clone +prefs: +- audiovm: "" +features: +- set: + - default-menu-items: "system-config-printer.desktop qubes-run-terminal.desktop qubes-open-file-manager.desktop qubes.start.desktop" + - menu-items: "system-config-printer.desktop qubes-run-terminal.desktop qubes-open-file-manager.desktop qubes.start.desktop" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: dvm-{{ slsdotpath }} +force: True +require: +- sls: {{ slsdotpath }}.clone +present: +- template: tpl-{{ slsdotpath }} +- label: red +prefs: +- template: tpl-{{ slsdotpath }} +- label: red +- netvm: "*default*" +- audiovm: "" +- vcpus: 1 +- memory: 300 +- maxmem: 400 +- autostart: False +- template_for_dispvms: True +- include_in_backups: True +features: +- enable: + - servicevm + - service.cups + - appmenus-dispvm +- disable: + - service.cups-browsed + - service.tinyproxy + - service.tracker + - service.evolution-data-server +- set: + - menu-items: "system-config-printer.desktop qubes-run-terminal.desktop qubes-open-file-manager.desktop qubes.start.desktop" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: disp-{{ slsdotpath }} +force: True +require: +- sls: {{ slsdotpath }}.clone +present: +- template: dvm-{{ slsdotpath }} +- label: red +- class: DispVM +prefs: +- template: dvm-{{ slsdotpath }} +- label: red +- netvm: "*default*" +- audiovm: "" +- vcpus: 1 +- memory: 300 +- maxmem: 400 +- autostart: False +- include_in_backups: True +features: +- enable: + - servicevm + - service.cups +- disable: + - service.cups-browsed + - service.tinyproxy + - service.tracker + - service.evolution-data-server +- set: + - menu-items: "system-config-printer.desktop qubes-run-terminal.desktop qubes-open-file-manager.desktop qubes.start.desktop" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: {{ slsdotpath }} +force: True +require: +- sls: {{ slsdotpath }}.clone +present: +- template: tpl-{{ slsdotpath }} +- label: red +prefs: +- template: tpl-{{ slsdotpath }} +- label: red +- netvm: "*default*" +- audiovm: "" +- vcpus: 1 +- memory: 300 +- maxmem: 400 +- autostart: False +- include_in_backups: True +features: +- enable: + - servicevm + - service.cups +- disable: + - service.cups-browsed + - service.tinyproxy + - service.tracker + - service.evolution-data-server +- set: + - menu-items: "system-config-printer.desktop qubes-run-terminal.desktop qubes-open-file-manager.desktop qubes.start.desktop" +{%- endload %} +{{ load(defaults) }} + +{% from 'utils/macros/policy.sls' import policy_set with context -%} +{{ policy_set(sls_path, '80') }} diff --git a/salt/sys-print/create.top b/salt/sys-print/create.top new file mode 100644 index 00000000..421f88f3 --- /dev/null +++ b/salt/sys-print/create.top @@ -0,0 +1,10 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dom0': + - match: nodegroup + - sys-print.create diff --git a/salt/sys-print/files/admin/policy/default.policy b/salt/sys-print/files/admin/policy/default.policy new file mode 100644 index 00000000..d9b350d8 --- /dev/null +++ b/salt/sys-print/files/admin/policy/default.policy @@ -0,0 +1,9 @@ +# SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +## Do not modify this file, create a new policy with with a lower number in the +## file name instead. For example `30-user.policy`. +qusal.Print * @anyvm @default ask default_target=sys-print +qusal.Print * @anyvm @anyvm deny +## vim:ft=qrexecpolicy diff --git a/salt/sys-print/files/client/systemd/qubes-print-forwarder.service b/salt/sys-print/files/client/systemd/qubes-print-forwarder.service new file mode 100644 index 00000000..dbd9d23d --- /dev/null +++ b/salt/sys-print/files/client/systemd/qubes-print-forwarder.service @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2023 unman +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=Print over Qrexec +After=qubes-qrexec-agent.service +ConditionPathExists=/var/run/qubes-service/print-setup + +[Service] +ExecStart=/usr/bin/socat TCP4-LISTEN:631,reuseaddr,fork,end-close EXEC:"qrexec-client-vm @default qusal.Print" +Restart=on-failure +RestartSec=3 + +# Hardening +ProtectSystem=full +PrivateTmp=true +SystemCallArchitectures=native +MemoryDenyWriteExecute=true +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target diff --git a/salt/sys-print/files/server/qubes-bind-dirs.d/50-sys-print.conf b/salt/sys-print/files/server/qubes-bind-dirs.d/50-sys-print.conf new file mode 100644 index 00000000..07779284 --- /dev/null +++ b/salt/sys-print/files/server/qubes-bind-dirs.d/50-sys-print.conf @@ -0,0 +1,7 @@ +# SPDX-FileCopyrightText: 2023 unman +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +binds+=('/etc/cups') + +# vim: ft=bash diff --git a/salt/sys-print/files/server/rpc/qusal.Print b/salt/sys-print/files/server/rpc/qusal.Print new file mode 100644 index 00000000..7ffca48a --- /dev/null +++ b/salt/sys-print/files/server/rpc/qusal.Print @@ -0,0 +1,7 @@ +#!/bin/sh +# SPDX-FileCopyrightText: 2023 unman +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +set -eu +exec socat STDIO TCP:localhost:631 diff --git a/salt/sys-print/init.top b/salt/sys-print/init.top new file mode 100644 index 00000000..714de1ac --- /dev/null +++ b/salt/sys-print/init.top @@ -0,0 +1,14 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dom0': + - match: nodegroup + - sys-print.create + 'tpl-sys-print': + - sys-print.install + 'dvm-sys-print,sys-print': + - sys-print.configure diff --git a/salt/sys-print/install-client.sls b/salt/sys-print/install-client.sls new file mode 100644 index 00000000..157ee92d --- /dev/null +++ b/salt/sys-print/install-client.sls @@ -0,0 +1,15 @@ +{# +SPDX-FileCopyrightText: 2022 - 2023 unman +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +"{{ slsdotpath }}-systemd-print-forwarder": + file.managed: + - name: /usr/lib/systemd/system/qubes-print-forwarder.service + - source: salt://{{ slsdotpath }}/files/client/systemd/qubes-print-forwarder.service + - mode: '0644' + - user: root + - group: root + - makedirs: True diff --git a/salt/sys-print/install-client.top b/salt/sys-print/install-client.top new file mode 100644 index 00000000..29f186ed --- /dev/null +++ b/salt/sys-print/install-client.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + '*': + - sys-print.install-client diff --git a/salt/sys-print/install-driver-all.sls b/salt/sys-print/install-driver-all.sls new file mode 100644 index 00000000..38a32682 --- /dev/null +++ b/salt/sys-print/install-driver-all.sls @@ -0,0 +1,21 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' -%} + +include: + - sys-print.install + +"{{ slsdotpath }}-installed": + pkg.installed: + - require: + - sls: utils.tools.common.update + - install_recommends: False + - skip_suggestions: True + - pkgs: + - printer-driver-all-enforce + +{% endif -%} diff --git a/salt/sys-print/install-driver-all.top b/salt/sys-print/install-driver-all.top new file mode 100644 index 00000000..b2ec315c --- /dev/null +++ b/salt/sys-print/install-driver-all.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'tpl-sys-print': + - sys-print.install-driver-all diff --git a/salt/sys-print/install.sls b/salt/sys-print/install.sls new file mode 100644 index 00000000..024dd60e --- /dev/null +++ b/salt/sys-print/install.sls @@ -0,0 +1,44 @@ +{# +SPDX-FileCopyrightText: 2022 - 2023 unman +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' -%} + +include: + - utils.tools.common.update + - dev.home-cleanup + - dotfiles.copy-sh + - dotfiles.copy-x11 + - sys-usb.install-client + +"{{ slsdotpath }}-installed": + pkg.installed: + - require: + - sls: utils.tools.common.update + - install_recommends: False + - skip_suggestions: True + - pkgs: + ## Discovery + - qubes-core-agent-networking + - cups + - ipp-usb + ## Print + - printer-driver-cups-pdf + - system-config-printer + ## Scan + ## TODO: simple-scan did not detect my scanner, but detected printer. + - simple-scan + - sane + - sane-utils + - sane-airscan + +"{{ slsdotpath }}-add-user-to-lpadmin-group": + group.present: + - name: lpadmin + - addusers: + - user + +{% endif -%} diff --git a/salt/sys-print/install.top b/salt/sys-print/install.top new file mode 100644 index 00000000..655ab65f --- /dev/null +++ b/salt/sys-print/install.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'tpl-sys-print': + - sys-print.install