No network connection to download the proprietary HP plugin inside minimal template

I am facing a problem with hplip setup.

I need to install the hp-plugin from remote source ( connection stabilished inside the hp-setup) on the minimal Debian template, but I cannot connect even though I export proxy_https.


This is the script I am trying to fix to configure an HP printer:

hplip-usb-printer-qubes.sh

#!/bin/bash

################################################################################
# File Name    : hplip-usb-printer-qubes.sh
# Description  : This script creates a disposable qube for HP printers via USB
#                using hplip with semi-automatic hp-setup and plugin installation
#                for printers that require proprietary components with USB printer
#                detection and attachment.
# Dependencies : usbutils cups python3-pyqt5 hplip-gui
# Usage        : • Transfer from appvm to dom0:
#                qvm-run -p appvm 'cat ~/hplip-usb-printer-qubes.sh' > ~/hplip-usb-printer-qubes.sh
#                • Make executable:
#                chmod +x ~/hplip-usb-printer-qubes.sh
#                • Run:
#                bash ~/hplip-usb-printer-qubes.sh
# Author       : Me and the bois
# License      : Free of charge, no warranty
# Last edited  : 2025-10-05
################################################################################

# Safety check
set -eu

# Configuration
BASE_TEMPLATE="debian-12-minimal"
CUSTOM_TEMPLATE="debian-hplip-template"
DISP_TEMPLATE="debian-hplip-template-dvm"
NAMED_DISP_VM="disp-printer"

# 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: Verifying and creating base template: $BASE_TEMPLATE..."

    if ! qvm-check "$BASE_TEMPLATE"; then
        echo -e "\nInstalling $BASE_TEMPLATE..."
        sudo qubes-dom0-update "qubes-template-$BASE_TEMPLATE"
    fi

    qvm-shutdown --wait "$BASE_TEMPLATE"

    echo -e "\nUpdating $BASE_TEMPLATE..."
    sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm

    echo -e "\nBase template setup complete"
}

# Step 2: Create custom template
create_custom_template() {
    echo -e "\nStep 2: Creating $CUSTOM_TEMPLATE..."

    if ! qvm-check "$CUSTOM_TEMPLATE"; then
        echo -e "\nCreating $CUSTOM_TEMPLATE by cloning from $BASE_TEMPLATE..."
        qvm-clone "$BASE_TEMPLATE" "$CUSTOM_TEMPLATE"
    fi

    qvm-prefs "$CUSTOM_TEMPLATE" label yellow
    qvm-prefs "$CUSTOM_TEMPLATE" include_in_backups false
    qvm-service "$CUSTOM_TEMPLATE" cups on
    qvm-service "$CUSTOM_TEMPLATE" qubes-usb-proxy on

    echo -e "\nStarting $CUSTOM_TEMPLATE for package installation..."
    qvm-start "$CUSTOM_TEMPLATE"
}

# Step 3: Install system dependencies
install_system_dependencies() {
    echo -e "\nStep 3: Installing required packages in $CUSTOM_TEMPLATE..."

    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 basic packages (change as needed)
    echo -e "\nInstalling basic packages in $CUSTOM_TEMPLATE..."
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "
    apt install -y --no-install-recommends \
    qubes-core-agent-passwordless-root \
    qubes-core-agent-networking \
    qubes-usb-proxy \
    usbutils \
    thunar \
    qubes-core-agent-thunar \
    qpdfview \
    mousepad \
    less \
    psmisc \
    bash-completion \
    xfce4-terminal
"
}

# Step 4: Install printer dependencies in custom template
install_printer_dependencies() {
    echo -e "\nStep 4: Installing printing dependencies in $CUSTOM_TEMPLATE..."

    # Install printer package
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "
    apt install -y --no-install-recommends \
    cups \
    ipp-usb \
    python3-pyqt5 \
    hplip-gui \
    printer-driver-hpcups
"
}

# Step 5: Printer connection configuration
setup_printer_services() {
    echo -e "\nStep 5: Configuring printer services..."

    # Load services
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "systemctl enable cups"
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "systemctl start cups"

    # Group and permission settings
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "usermod -a -G lpadmin user"
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "mkdir -p /var/lib/hp"
    qvm-run -p -u root "$CUSTOM_TEMPLATE" "chown -R user:user /var/lib/hp"

    # Restart for fresh configurations and services
    qvm-shutdown --wait "$CUSTOM_TEMPLATE"
    qvm-start --skip-if-running "$CUSTOM_TEMPLATE"
    sleep 3

    # Find and attach USB with error checking
    DEVICE_ID=$(qvm-usb list | grep -i -E "03f0|Hewlett" | awk '{print $1}' | head -n 1)
    if [[ -z "$DEVICE_ID" ]]; then
        echo "Error: No HP USB device found. Please check printer connection."
        return 1
    fi

    if qvm-usb attach "$CUSTOM_TEMPLATE" "$DEVICE_ID"; then
        echo "Attached $DEVICE_ID to $CUSTOM_TEMPLATE."
    else
        echo "Error: Failed to attach USB device $DEVICE_ID"
        return 1
    fi
}

# Step 6: Run interactive setup
run_printer_setup() {
    echo -e "\nStep 6: Running printer setup..."

    if ! qvm-run -p "$CUSTOM_TEMPLATE" "hp-setup -i" 2>/dev/null; then
        echo "Warning: Printer setup encountered issues, but continuing..."
        echo ""
        echo "You can manually run 'hp-setup -i' later in the template."
        echo ""
    fi

    return 0  # Always return success to continue script
}

# Step 7: Function to 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-remove "$DISP_TEMPLATE" -f
    fi

    qvm-create --template "$CUSTOM_TEMPLATE" --label yellow "$DISP_TEMPLATE"
    qvm-prefs "$DISP_TEMPLATE" template_for_dispvms True
    qvm-prefs "$DISP_TEMPLATE" include_in_backups false
    qvm-service "$DISP_TEMPLATE" cups on
}

# Step 8: Function to 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-remove "$NAMED_DISP_VM" -f
    fi

    qvm-create --class DispVM --template "$DISP_TEMPLATE" --label yellow "$NAMED_DISP_VM"
    qvm-prefs "$NAMED_DISP_VM" netvm 'sys-whonix'  # Or your preferred netvm
    qvm-prefs "$NAMED_DISP_VM" include_in_backups false
    qvm-service "$NAMED_DISP_VM" cups on

    echo -e "\nNamed disposable VM '$NAMED_DISP_VM' created successfully"
}

# Finalization
finalize() {
    # Add menu items
    qvm-features "$CUSTOM_TEMPLATE" menu-items "hplip.desktop system-config-printer.desktop thunar.desktop xfce4-terminal.desktop"
    qvm-features "$DISP_TEMPLATE" menu-items "hplip.desktop system-config-printer.desktop thunar.desktop xfce4-terminal.desktop"
    qvm-features "$NAMED_DISP_VM" menu-items "hplip.desktop system-config-printer.desktop thunar.desktop xfce4-terminal.desktop"

    # Shutdown template
    qvm-shutdown --wait "$CUSTOM_TEMPLATE"

    echo -e "\nSetup completed successfully!"
    echo "Usage:"
    echo "Set your preferred netvm for printer configuration:"
    echo "   qvm-prefs $NAMED_DISP_VM netvm 'sys-whonix'"
    echo "Start named disposable template and printer setup:"
    echo "   qvm-run -q -a --service -- $NAMED_DISP_VM qubes.StartApp+hplip"
    echo "Attach printer to $NAMED_DISP_VM:"
    echo "   qvm-usb attach $NAMED_DISP_VM $DEVICE_ID"
}

# Main execution
main() {
    echo "Starting HP USB Printer Setup with Plugin Support"
    check_printer_attached
    create_base_template
    create_custom_template
    install_system_dependencies
    install_printer_dependencies
    setup_printer_services
    run_printer_setup
    create_dvm_template
    create_named_disposable
    finalize
    echo -e "\nSetup completed successfully!"
}

main "$@"


Is there a more private setup for those who depend on hplip and hp-plugin?

I've tried several things , e.g., USB-PPD connection almost any dependence or network connection. As a USB connected modern printer shouldn't be set up as a USB with PPD and driver if it is capable of IPP-over-USB (know as driverless or AirPrint), some drivers and are deprecated in CUPS and they will not be serviced.

I'm thinking in a setup with system-config-printer printer interface using USB-PPD connection with drives like, printer-driver-hpcups or foomatic-db .


Some references

Lessons learned: dont buy HP printers, buy a Brother laser printer. Never connect it to internet and never install or update backdoored-watering-hole-new-drives.

1 Like

Hplip is downloading the plugin and signature files from the http://www.openprinting.org/download/printdriver/auxfiles/HP/plugins/ using wget or curl command.
So you need to have either wget or curl installed and set http_proxy instead of https_proxy.
You can also download the plugin in a network-connected disposable qube, verify its signature, move it to the template and install it there using hp-plugin.

You should use qvm-template instead of qubes-dom0-update.

Why don’t you just use the qubes-vm-update?

There is no qubes-usb-proxy service in the Qubes OS.

2 Likes

That’s great, I didn’t know that existed.


==============================================================

Exactly what I’m will do.


==============================================================

From qubes documentation:

Installation

The minimal templates can be installed with the following type of command:

sudo qubes-dom0-update qubes-template-<DISTRO_NAME>-<RELEASE_NUMBER>-minimal


==============================================================

From qubes documentation:

We could use two ways, the old one and the new one:

Advanced users may wish to perform updates via the command-line interface. There are two ways to do this:

  • If you are using Salt, one can use the following two Salt states.
  • update.qubes-dom0
  • update.qubes-vm
  • Alternatively, use qubes-dom0-update to update dom0, and use qubes-vm-update to update domUs.

Using either of these methods has the same effect as updating via the Qubes Update tool.


==============================================================

From qubes documentation:

CORRECT !


==============================================================

Another day I’ll redo the script, testing and implementing everything automatically. I’ll post it another day, thanks.

1 Like

It’s outdated, seems like someone missed it when updating the documentation:

I think that qubes-vm-update is more abstract tool, compared to qubesctl command, which is using Salt specifically. Right now Qubes OS is using Salt, but it could change in the future, for example, to Ansible. So using qubes-vm-update instead of Salt directly wouldn’t break your script in the future.
But those are just my thoughts.

1 Like

How its going:

debian-hplip-named-diposable.sh

#!/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 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 "$@"

debian-hplip-named-diposable.sh.log (12.9 KB)


TL;DR CUPS Permission and Ownership

Key Security Concepts

The Root Access in Qubes and Printer Context

  • Qubes RPC: direct root access via qvm-run -u root.
  • Passwordless sudo: qubes-core-agent-passwordless-root package allows passwordless sudo within the VM.
  • CUPS/HPLIP: require root privileges for installation and service configuration.
  • UDEV device controls: USB printers access.
  • PolicyKit: for specific GUI applications (HPLIP Toolbox).

Service Security Model

Principle of Least Privilege:

  • Configuration files owned by root but readable by lp group

Access Control:

  • Administrative tasks: Users in root group (via SystemGroup)
  • Printer operations: Users in lp group
  • Log access: Users in adm group

USB Device Access

UDEV Rules:

# HP USB printers get lp group ownership
SUBSYSTEM=="usb", ATTRS{idVendor}=="03f0", GROUP="lp", MODE="0664"
  • Effect: Any HP printer (vendor ID 03f0) becomes accessible to lp group members
  • Permissions: Read/write for owner and group, read-only for others

PolicyKit Integration

For specific GUI applications.

Rule:

// Allow passwordless printer administration for:
polkit.addRule(function(action, subject) {
  if (subject.isInGroup("user") ||  // Regular users
  subject.isInGroup("lp") ||  // Printer group members
  subject.user == "root") {   // System administrator
  return polkit.Result.YES;   // Grant permission
  }
});

User and Group Structure

Users:

  • cups (UID 999) - Dedicated CUPS service account
    • Created: useradd -r -c 'CUPS Printing Service' -s /bin/false -d /var/spool/cups cups
    • Purpose: Runs CUPS daemon with minimal privileges (CUPS security requirement)
  • user (UID 1000) - Regular user account
    • Added to lp group for printer administration
    • Be careful to keep the file ownership to root:lp.
  • root (UID 0) - System administrator
    • Has full access via SystemGroup root

Groups:

  • lp (GID 7) - Primary printing group
    • Members: cups, user, root
    • Purpose: Allows printer access and administration
  • root - System administrators group
  • adm - Log file access group

File and Directory Permissions

CUPS Configuration:

/etc/cups/
├── cupsd.conf         (root:lp, 644)
├── cups-files.conf   (root:lp, 644)
└── [other configs]     (root:lp, 644)

Runtime Directories:

/var/log/cups/         (cups:lp, 755)   - Log files
/var/cache/cups/      (cups:lp, 755)   - Temporary files
/var/spool/cups/      (cups:lp, 755)   - Print jobs spool
References

Note: you can extract and study the installer code without running it by using, e.g.,bash /tmp/hplip-$VERSION.run --noexec. It'll extract into a directory named /tmp/hplip-$VERSION


  [user@host ~]$ chmod +x /home/user/hplip-3.25.8.run
  [user@host ~]$ /home/user/hplip-3.25.8.run --help
Makeself version 2.4.0
 1) Getting help or info about /home/user/hplip-3.25.8.run :
  /home/user/hplip-3.25.8.run --help   Print this message
  /home/user/hplip-3.25.8.run --info   Print embedded info : title, default target directory, embedded script ...
  /home/user/hplip-3.25.8.run --lsm    Print embedded lsm entry (or no LSM)
  /home/user/hplip-3.25.8.run --list   Print the list of files in the archive
  /home/user/hplip-3.25.8.run --check  Checks integrity of the archive

 2) Running /home/user/hplip-3.25.8.run :
  /home/user/hplip-3.25.8.run [options] [--] [additional arguments to embedded script]
  with following options (in that order)
  --confirm             Ask before running embedded script
  --quiet		Do not print anything except error messages
  --accept              Accept the license
  --noexec              Do not run embedded script
  --keep                Do not erase target directory after running
			the embedded script
  --noprogress          Do not show the progress during the decompression
  --nox11               Do not spawn an xterm
  --nochown             Do not give the extracted files to the current user
  --nodiskspace         Do not check for available disk space
  --target dir          Extract directly to a target directory (absolute or relative)
                        This directory may undergo recursive chown (see --nochown).
  --tar arg1 [arg2 ...] Access the contents of the archive through the tar command
  --                    Following arguments will be passed to the embedded script