#!/bin/bash ################################################################################ # File Name : debian-hplip-named-diposable.sh # Description : This script creates a disposable qube for HP printers via USB # using Debian's packaged hplip and hpli-gui with download and # installation of hp-plugin from Open Printing. This is script # requires interation to accept EULA policies. Note, you must # use plugin version that matches Debian HPLIP version. # Usage : • Transfer from appvm to dom0: # qvm-run -p appvm 'cat ~/debian-hplip-named-diposable.sh' > ~/debian-hplip-named-diposable.sh # • Make executable: # chmod +x ~/debian-hplip-named-diposable.sh # • Run: # bash ~/debian-hplip-named-diposable.sh # Author : Me and the bois # License : Free of charge, no warranty ################################################################################ # Security first set -e # Configuration BASE_TEMPLATE="debian-12-minimal" CUSTOM_TEMPLATE="debian-hplip-template" DISP_TEMPLATE="debian-hplip-template-dvm" NAMED_DISP_VM="disp-hplip" # Plugin URL for Debian HPLIP version PLUGIN_URL="https://www.openprinting.org/download/printdriver/auxfiles/HP/plugins/hplip-3.22.10-plugin.run" # Ensure printer is connected via USB and powered on check_printer_attached() { echo -e "\nPrinter Check..." if qvm-usb 2>/dev/null | grep -q -i -E "03f0|Hewlett"; then echo "HP printer detected" return 0 else echo "No HP printer detected" echo "Please connect HP printer via USB and ensure it's powered on" return 1 fi } # Step 1: Verify and create base template create_base_template() { echo -e "\nStep 1: Setting up base template $BASE_TEMPLATE..." if ! qvm-check "$BASE_TEMPLATE" 2>/dev/null; then echo "Installing $BASE_TEMPLATE..." sudo qubes-dom0-update "qubes-template-$BASE_TEMPLATE" fi # Ensure template is shut down before updating qvm-shutdown --wait "$BASE_TEMPLATE" 2>/dev/null || true if qvm-check "$BASE_TEMPLATE"; then echo "Updating $BASE_TEMPLATE..." sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm fi echo -e "\nBase template setup complete" } # Step 2: Create custom base template create_custom_template() { echo -e "\nStep 2: Creating $CUSTOM_TEMPLATE..." if ! qvm-check "$CUSTOM_TEMPLATE"; then qvm-clone "$BASE_TEMPLATE" "$CUSTOM_TEMPLATE" fi qvm-prefs "$CUSTOM_TEMPLATE" label black qvm-prefs "$CUSTOM_TEMPLATE" include_in_backups false qvm-service "$CUSTOM_TEMPLATE" cups on qvm-service "$CUSTOM_TEMPLATE" avahi on qvm-start "$CUSTOM_TEMPLATE" } # Step 3: Install packages in template (change as needed) install_system_dependencies() { echo -e "\nStep 3: Installing packages in $CUSTOM_TEMPLATE..." # Basic system configuration echo "Configuring system environment..." qvm-run -p -u root "$CUSTOM_TEMPLATE" "echo 'TERM=xterm' >> /etc/environment" qvm-run -p -u root "$CUSTOM_TEMPLATE" "sed -i 's/^# *\(en_US.UTF-8\)/\1/' /etc/locale.gen" qvm-run -p -u root "$CUSTOM_TEMPLATE" "locale-gen en_US.UTF-8" # Install core packages echo "Installing core packages..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " apt-get install -y --no-install-recommends \ qubes-core-agent-passwordless-root \ qubes-core-agent-networking \ qubes-usb-proxy \ dbus \ dbus-x11 \ python3 \ thunar \ qubes-core-agent-thunar \ mousepad \ qpdfview \ less \ psmisc \ bash-completion \ xfce4-terminal " } # Step 4: Install packages install_hplip_from_apt() { echo -e "\nStep 4: Installing CUPS and essential libraries..." # Install CUPS and essential libraries echo "Installing CUPS and essential libraries..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " apt-get install -y --no-install-recommends \ cups \ cups-client \ libcups2 \ libcupsimage2 \ libdbus-1-3 \ libjpeg62-turbo \ libusb-1.0-0 \ libsane1 \ avahi-daemon \ avahi-utils " # Install HPLIP CLI echo "Installing HPLIP CLI..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " apt-get install -y --no-install-recommends \ hplip \ python3-dbus \ python3-pil \ python3-reportlab " # Installing HPLIP GUI echo "Installing HPLIP GUI..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl \ pkexec \ polkitd \ policykit-1 \ cups-pk-helper \ python3-pyqt5 \ hplip-gui " } # Step 5: Installing HP plugin from remote source download_and_install_plugin() { echo -e "\nStep 5: Installing HP plugin..." echo "Using plugin version that matches Debian HPLIP version" echo "Downloading plugin from: $PLUGIN_URL" qvm-start --skip-if-running "$CUSTOM_TEMPLATE" # Attach HP printer if available (TODO: use variables for device id) DEVICE_ID=$(qvm-usb list | grep -i -E "03f0|Hewlett" | awk '{print $1}' | head -n 1) if [ -n "$DEVICE_ID" ]; then qvm-usb attach "$CUSTOM_TEMPLATE" "$DEVICE_ID" echo "Attached printer $DEVICE_ID to $CUSTOM_TEMPLATE" fi # Download plugin as root (TODO: dinamically download matching hplip version) qvm-run -p -u root "$CUSTOM_TEMPLATE" " cd /tmp && curl -x http://127.0.0.1:8082/ \ --retry 5 \ --retry-delay 2 \ --retry-max-time 30 \ --connect-timeout 20 \ --max-time 300 \ --continue-at - \ --output hplip-3.22.10-plugin.run \ '$PLUGIN_URL' " # Extract and install plugin with interactive prompts (TODO: noninteractive dont work, even extracting) echo "Installing plugin as root with interactive prompts..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " chmod +x /tmp/hplip-3.22.10-plugin.run DEBIAN_FRONTEND=noninteractive bash /tmp/hplip-3.22.10-plugin.run " # Cleanup files qvm-run -p "$CUSTOM_TEMPLATE" "rm -rf /tmp/hplip-*" 2>/dev/null || true echo "Plugin installation completed successfully" } # Step 6: Service permissions and authentication configuration setup_printer_services() { echo -e "\nStep 6: Configuring printer services..." # Create proper user echo "Configuring CUPS services..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " # Create cups user in correct group useradd -r -c 'CUPS printing service' -d /var/spool/cups -g lp -s /bin/false cups # Add cups user to lp group usermod -a -G lp cups # Add user to lp group for printer administration usermod -a -G lp user # Stop any running cups services systemctl stop cups cups.socket cups.path 2>/dev/null || true systemctl reset-failed cups cups.socket cups.path 2>/dev/null || true " # Create cups-files.conf using mktemp echo "Configuring CUPS settings..." local cups_files_conf=$(mktemp) cat > "$cups_files_conf" << 'EOF' # Default user and group for filters/backends/helper programs User cups Group lp # Administrator user group SystemGroup root # Log file group LogFileGroup adm # Spool directory RequestRoot /var/spool/cups EOF qvm-copy-to-vm "$CUSTOM_TEMPLATE" "$cups_files_conf" qvm-run -p -u root "$CUSTOM_TEMPLATE" "mv /home/user/QubesIncoming/dom0/$(basename "$cups_files_conf") /etc/cups/cups-files.conf" rm -f "$cups_files_conf" # Create cupsd.conf using mktemp echo "Configuring CUPS daemon settings..." local cupsd_conf=$(mktemp) cat > "$cupsd_conf" << 'EOF' LogLevel warn MaxLogSize 0 Listen localhost:631 Listen /run/cups/cups.sock Browsing Off DefaultAuthType Basic WebInterface No # Default print settings DefaultPageSize A4 Order allow,deny Allow all Order allow,deny Allow all AuthType Default Require user @SYSTEM Order allow,deny Allow all JobPrivateAccess default JobPrivateValues default SubscriptionPrivateAccess default SubscriptionPrivateValues default Order allow,deny Allow all EOF qvm-copy-to-vm "$CUSTOM_TEMPLATE" "$cupsd_conf" qvm-run -p -u root "$CUSTOM_TEMPLATE" "mv /home/user/QubesIncoming/dom0/$(basename "$cupsd_conf") /etc/cups/cupsd.conf" rm -f "$cupsd_conf" # Directory permissions with correct ownership echo "Configuring CUPS permissions and ownership..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " chmod 644 /etc/cups/cupsd.conf /etc/cups/cups-files.conf mkdir -p /var/log/cups /var/cache/cups /var/spool/cups chown -R cups:lp /var/log/cups /var/cache/cups /var/spool/cups chown -R root:lp /etc/cups chmod 755 /var/log/cups /var/cache/cups /var/spool/cups # Ensure cups spool directory has correct permissions chown cups:lp /var/spool/cups chmod 755 /var/spool/cups " # Configure udev rules for USB printer devices using mktemp echo "Configuring USB permissions..." local udev_rules=$(mktemp) cat > "$udev_rules" << 'EOF' # HP USB printer permissions SUBSYSTEM=="usb", ATTRS{idVendor}=="03f0", GROUP="lp", MODE="0664" SUBSYSTEM=="usb", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="*", GROUP="lp", MODE="0664" EOF qvm-copy-to-vm "$CUSTOM_TEMPLATE" "$udev_rules" qvm-run -p -u root "$CUSTOM_TEMPLATE" " mv /home/user/QubesIncoming/dom0/$(basename "$udev_rules") /etc/udev/rules.d/99-hp-usb-printer.rules udevadm control --reload-rules udevadm trigger " rm -f "$udev_rules" # Configure PolicyKit for passwordless printer administration echo "Configuring PolicyKit..." qvm-run -p -u root "$CUSTOM_TEMPLATE" "mkdir -p /etc/polkit-1/rules.d" # Create PolicyKit rules using mktemp local polkit_rules=$(mktemp) cat > "$polkit_rules" << 'EOF' // Allow any action for qubes users and printer groups polkit.addRule(function(action, subject) { if (subject.isInGroup("user") || subject.isInGroup("lp") || subject.user == "root") { return polkit.Result.YES; } }); EOF qvm-copy-to-vm "$CUSTOM_TEMPLATE" "$polkit_rules" qvm-run -p -u root "$CUSTOM_TEMPLATE" " mv /home/user/QubesIncoming/dom0/$(basename "$polkit_rules") /etc/polkit-1/rules.d/99-qubes-allow-all.rules chmod 644 /etc/polkit-1/rules.d/99-qubes-allow-all.rules rm -f /home/user/QubesIncoming/dom0/$(basename "$polkit_rules") " rm -f "$polkit_rules" # Configure and start services echo "Starting printer services..." qvm-run -p -u root "$CUSTOM_TEMPLATE" " # Verify configuration echo 'Verifying CUPS configuration...' if cupsd -t; then echo 'CUPS configuration test PASSED' else echo 'CUPS configuration test FAILED, checking details...' cupsd -t 2>&1 exit 1 fi # Reset any failed services systemctl reset-failed cups cups.socket cups.path 2>/dev/null || true # Enable services systemctl enable cups.socket systemctl enable cups.path systemctl enable avahi-daemon systemctl enable dbus # Start services in correct order systemctl start dbus systemctl start avahi-daemon systemctl start cups.socket systemctl start cups.path sleep 3 systemctl start cups sleep 3 systemctl status cups --no-pager -l " echo "Printer services configuration completed" } # Step 7: Create DVM template create_dvm_template() { echo -e "\nStep 7: Creating DVM template..." qvm-shutdown --wait "$CUSTOM_TEMPLATE" if ! qvm-check "$DISP_TEMPLATE" 2>/dev/null; then qvm-create --template "$CUSTOM_TEMPLATE" --label red "$DISP_TEMPLATE" fi qvm-prefs "$DISP_TEMPLATE" template_for_dispvms True qvm-prefs "$DISP_TEMPLATE" include_in_backups false qvm-service "$DISP_TEMPLATE" cups on qvm-service "$DISP_TEMPLATE" avahi on echo -e "\nTemplate for disposables '$DISP_TEMPLATE' created successfully" } # Step 8: Create named disposable VM create_named_disposable() { echo -e "\nStep 8: Creating named disposable VM..." if ! qvm-check "$NAMED_DISP_VM" 2>/dev/null; then qvm-create --template "$DISP_TEMPLATE" --class DispVM --label blue \ --property netvm="" \ --property vcpus=1 \ --property memory=128 \ --property maxmem=512 \ --property autostart=False \ --property include_in_backups=False \ "$NAMED_DISP_VM" fi qvm-service "$NAMED_DISP_VM" cups on qvm-service "$NAMED_DISP_VM" avahi on echo -e "\nNamed disposable VM '$NAMED_DISP_VM' created successfully" } # Finalization finalize() { echo -e "\nStep 9: Finalizing setup..." # Sync appmenus and shutdown qvm-start --skip-if-running "$CUSTOM_TEMPLATE" qvm-sync-appmenus "$CUSTOM_TEMPLATE" qvm-shutdown --wait "$CUSTOM_TEMPLATE" qvm-start --skip-if-running "$NAMED_DISP_VM" qvm-sync-appmenus "$NAMED_DISP_VM" qvm-shutdown --wait "$NAMED_DISP_VM" # Configure menu items qvm-features "$CUSTOM_TEMPLATE" menu-items "xfce4-terminal.desktop" qvm-features "$DISP_TEMPLATE" menu-items "xfce4-terminal.desktop" qvm-features "$NAMED_DISP_VM" menu-items "hplip.desktop thunar.desktop xfce4-terminal.desktop" } # Main execution main() { echo "Starting HP USB Printer Setup" check_printer_attached create_base_template create_custom_template install_system_dependencies install_hplip_from_apt download_and_install_plugin setup_printer_services create_dvm_template create_named_disposable finalize echo -e "\nSetup completed successfully!" } main "$@"