Tweak: Better supported syntax for URI on Linux
[einar-bin] / addfollowmeprint.sh
index 7dce648335ddae6009bd1df1311722f7edcd0d02..035767d74655e860fe0606b66f7bb70fae2387b5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 # This script installs the FollowMe print queue at NTNU on Linux (and possibly Mac) systems.
 # The targeted and tested distros are: Debian, Ubuntu (and derivates), Fedora, CentOS, OpenSUSE and Mint
 #!/bin/bash
 # This script installs the FollowMe print queue at NTNU on Linux (and possibly Mac) systems.
 # The targeted and tested distros are: Debian, Ubuntu (and derivates), Fedora, CentOS, OpenSUSE and Mint
-# Copyright © 2017 einar.haraldseid@ntnu.no
+# Copyright © 2017-2019 einar.haraldseid@ntnu.no
 
 # Documentation
 function usage {
 
 # Documentation
 function usage {
@@ -10,6 +10,7 @@ function usage {
   echo " -m, --model {ricoh|generic}     Printer model to install (default: generic)"
   echo " -d, --driver {pcl,postscript}   Printer driver to use (default: postscript)"
   echo " -f, --force                     Force running script as if on Linux systems"
   echo " -m, --model {ricoh|generic}     Printer model to install (default: generic)"
   echo " -d, --driver {pcl,postscript}   Printer driver to use (default: postscript)"
   echo " -f, --force                     Force running script as if on Linux systems"
+  echo " -p, --plaintext                 Store credentials as plaintext in /etc/cups/printers.conf (Linux only)"
   echo " -h, --help                      Display this help text"
 }
 
   echo " -h, --help                      Display this help text"
 }
 
@@ -18,21 +19,15 @@ function printerror() {
   echo "${*}" 1>&2
 }
 
   echo "${*}" 1>&2
 }
 
-# Test for root
-if [ ${UID} -ne 0 ] ; then
-  echo "This script must be run as root, relaunching with sudo:" 
-  sudo bash "$0" "$@"
-  exit $?
-fi
-
 # Set default options that may be overridden by passed options below
 Model="generic"
 Driver="postscript"
 
 # Set other default options
 PrintServer="followprint.win.ntnu.no"
 # Set default options that may be overridden by passed options below
 Model="generic"
 Driver="postscript"
 
 # Set other default options
 PrintServer="followprint.win.ntnu.no"
-PrintName="FollowMe"
+PrintFile="ntnuprint-ricoh"
 Workgroup="WIN-NTNU-NO"
 Workgroup="WIN-NTNU-NO"
+QueueName="FollowMe"
 
 while [[ $# -gt 0 ]]; do
   Key="${1}"
 
 while [[ $# -gt 0 ]]; do
   Key="${1}"
@@ -56,15 +51,19 @@ while [[ $# -gt 0 ]]; do
         printerror "Unknown driver ${Driver}, plase choose one of postscript or pcl"
         exit 1
       fi
         printerror "Unknown driver ${Driver}, plase choose one of postscript or pcl"
         exit 1
       fi
-      shift # Jump to next option
+      shift # Jump to next argument
+      ;;
+    -p|--plaintext)
+      Plaintext="YES"
+      shift # Jump to next argument
       ;;
     -h|--help)
       usage
       exit 0
       ;;
     *)
       ;;
     -h|--help)
       usage
       exit 0
       ;;
     *)
-      # unknown option
-      echo "Unknown option: ${Key}"
+      # Unknown argument
+      echo "Unknown argument: ${Key}"
       exit 1
       ;;
   esac
       exit 1
       ;;
   esac
@@ -72,6 +71,26 @@ while [[ $# -gt 0 ]]; do
   shift # past argument or value
 done
 
   shift # past argument or value
 done
 
+# Make sure we have sudo powers when we need it
+if ! sudo -k; then
+  printerror "This script requires sudo to function"
+  exit 1
+fi
+
+# But don't run as super user, otherwise we can't access the keyring
+if [ ${UID} -eq 0 ]; then
+  if [ "${Plaintext}" != "YES" ]; then
+    printerror "Please run this script as your normal user, we will prompt you for your sudo password when needed. Or you can use the --plaintext option"
+    exit 1
+  fi
+else
+  echo "Please provide sudo password, as some parts of this script requires it"
+  if ! sudo true; then
+    printerror "Sorry, this script requires working sudo privileges to function"
+    exit 1
+  fi
+fi
+
 # Test for supported OS
 Uname=$(uname | tr "[:upper:]" "[:lower:]")
 if [ "${Uname}" != "darwin" ] && [ "${Uname}" != "linux" ] && [ "${Force}" != "YES" ]; then
 # Test for supported OS
 Uname=$(uname | tr "[:upper:]" "[:lower:]")
 if [ "${Uname}" != "darwin" ] && [ "${Uname}" != "linux" ] && [ "${Force}" != "YES" ]; then
@@ -80,17 +99,10 @@ if [ "${Uname}" != "darwin" ] && [ "${Uname}" != "linux" ] && [ "${Force}" != "Y
 fi
 
 # Set Uname to linux if we are forcing running the script
 fi
 
 # Set Uname to linux if we are forcing running the script
-if [ "${Force}" != "YES" ]; then
+if [ "${Force}" = "YES" ]; then
   Uname="linux"
 fi
 
   Uname="linux"
 fi
 
-# Set printer share based on model (generic goes to ntnuprint-xerox)
-if [ "${Model}" = "ricoh" ]; then
-  PrintShare="ntnuprint-ricoh"
-else
-  PrintShare="ntnuprint-xerox"
-fi
-
 # Set printer driver path based on driver (we will override these if we're specific distros
 if [ "${Driver}" = "postscript" ]; then
   DriverPath="drv:///sample.drv/generic.ppd"
 # Set printer driver path based on driver (we will override these if we're specific distros
 if [ "${Driver}" = "postscript" ]; then
   DriverPath="drv:///sample.drv/generic.ppd"
@@ -99,7 +111,7 @@ else
 fi
 
 # Test for CUPS
 fi
 
 # Test for CUPS
-if ! command -v lpadmin > /dev/null 2>&1; then
+if ! sudo bash -c "command -v lpadmin" > /dev/null 2>&1; then
   printerror "You must have CUPS installed to add printers. Please install CUPS."
   exit 1
 fi
   printerror "You must have CUPS installed to add printers. Please install CUPS."
   exit 1
 fi
@@ -112,24 +124,31 @@ if [ "${Uname}" = "linux" ]; then
     exit 1
   fi
 
     exit 1
   fi
 
-  # Try to determine if the necessary printer drivers are installed, and set alternate driver paths
-  # This should match OpenSUSE, and probably SUSE Enterprise, and other derivates that use yast2 as the primary package 
-  if command -v yast2 >/dev/null 2>&1; then
+  # Test if secret-tool is installed
+  if ! command -v secret-tool >/dev/null 2>&1; then
+    printerror "You must have secret-tool installed for this script to work. Please install libsecret-tools (Debian-systems) or secret-tool (Fedora/CentOS)."
+    exit 1
+  fi
+
+  # Try to determine if the necessary printer drivers are installed, and set correct driver paths
+
+  # This should match OpenSUSE, and probably SUSE Enterprise, and other derivates that use zypper as the primary package manager
+  if command -v zypper >/dev/null 2>&1; then
     if [ "${Driver}" = "postscript" ]; then
     if [ "${Driver}" = "postscript" ]; then
-      if ! rpm -q OpenPrintingPPDs-postscript >/dev/null 2>&1; then
-        printerror "You don't seem to have the correct printer drivers installed, please run:"
-        printerror "  sudo zypper install OpenPrintingPPDs-postscript"
-        printerror "first, or use the generic driver instead."
-        exit 1
-      else
-        if [ "${Model}" = "ricoh" ]; then
-          DriverPath="OpenPrintingPPDs/postscript/Ricoh-MP_C6003.Postscript-Ricoh.ppd.gz"
+      if [ "${Model}" = "ricoh" ]; then
+        if ! sudo rpm -q OpenPrintingPPDs-postscript >/dev/null 2>&1; then
+          printerror "You don't seem to have the correct printer drivers installed, please run:"
+          printerror "  sudo zypper install OpenPrintingPPDs-postscript"
+          printerror "first, or use the generic driver instead."
+          exit 1
         else
         else
-          DriverPath="OpenPrintingPPDs/postscript/Generic-PostScript_Printer.Postscript.ppd.gz"
+          DriverPath="OpenPrintingPPDs/postscript/Ricoh-MP_C6003.Postscript-Ricoh.ppd.gz"
         fi
         fi
+      else
+        DriverPath="Postscript.ppd.gz"
       fi
     else
       fi
     else
-      if ! rpm -q OpenPrintingPPDs-ghostscript >/dev/null 2>&1; then
+      if ! sudo rpm -q OpenPrintingPPDs-ghostscript >/dev/null 2>&1; then
         printerror "You don't seem to have the correct printer drivers installed, please run:"
         printerror "  sudo zypper install OpenPrintingPPDs-ghostscript"
         printerror "first, or use the generic driver instead."
         printerror "You don't seem to have the correct printer drivers installed, please run:"
         printerror "  sudo zypper install OpenPrintingPPDs-ghostscript"
         printerror "first, or use the generic driver instead."
@@ -142,134 +161,174 @@ if [ "${Uname}" = "linux" ]; then
         fi
       fi
     fi
         fi
       fi
     fi
-  fi
-  # The rest of the tests ignore the model test (all other distros support drv:///)
-  if [ "${Model}" != "generic" ]; then
-    # This should match Fedora and other modern rpm based systems that have dnf as the primary package manager
-    if command -v dnf >/dev/null 2>&1; then
-      if ! rpm -q foomatic-db-ppds 2>&1; then
-        printerror "You don't seem to have the correct printer drivers installed, please run:"
-        printerror "  sudo dnf install foomatic-db-ppds"
-        printerror "first, or use the generic driver instead."
-        exit 1
-      else
-        if [ "${Driver}" = "postscript" ]; then
-          DriverPath="foomatic-db-ppds/Ricoh/PS/Ricoh-MP_C6003_PS.ppd.gz"
+  else
+    # The rest of the systems can use drv:/// paths for the generic drivers, but we need to detect various distros for advice on installing Ricoh drivers
+    if [ "${Model}" = "ricoh" ]; then
+      # This should match Fedora and other modern rpm based systems that have dnf as the primary package manager
+      if command -v dnf >/dev/null 2>&1; then
+        if ! sudo rpm -q foomatic-db-ppds 2>&1; then
+          printerror "You don't seem to have the correct printer drivers installed, please run:"
+          printerror "  sudo dnf install foomatic-db-ppds"
+          printerror "first, or use the generic driver instead."
+          exit 1
         else
         else
-          DriverPath="foomatic-db-ppds/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd.gz"
+          if [ "${Driver}" = "postscript" ]; then
+            DriverPath="foomatic-db-ppds/Ricoh/PS/Ricoh-MP_C6003_PS.ppd.gz"
+          else
+            DriverPath="foomatic-db-ppds/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd.gz"
+          fi
         fi
       fi
         fi
       fi
-    fi
-    # This should match CentOS, RHEL and other RHEL based distros that have yum as the primary package manager
-    if command -v yum >/dev/null 2>&1; then
-      if ! rpm -q foomatic-db-ppds >/dev/null 2>&1; then
-        printerror "You don't seem to have the correct printer drivers installed, please run:"
-        printerror "  sudo yum install foomatic-db-ppds"
-        printerror "first, or use the generic driver instead."
-        exit 1
-      else
-        if [ "${Driver}" = "postscript" ]; then
-          DriverPath="foomatic-db-ppds/Ricoh/PS/Ricoh-MP_C6003_PS.ppd.gz"
+      # This should match CentOS, RHEL and other RHEL based distros that have yum as the primary package manager
+      if command -v yum >/dev/null 2>&1; then
+        if ! sudo rpm -q foomatic-db-ppds >/dev/null 2>&1; then
+          printerror "You don't seem to have the correct printer drivers installed, please run:"
+          printerror "  sudo yum install foomatic-db-ppds"
+          printerror "first, or use the generic driver instead."
+          exit 1
         else
         else
-          DriverPath="foomatic-db-ppds/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd.gz"
+          if [ "${Driver}" = "postscript" ]; then
+            DriverPath="foomatic-db-ppds/Ricoh/PS/Ricoh-MP_C6003_PS.ppd.gz"
+          else
+            DriverPath="foomatic-db-ppds/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd.gz"
+          fi
         fi
       fi
         fi
       fi
-    fi
-     # This should match Debian, Ubuntu and most if not all derivates that use dpkg as the primary package manager
-    if command -v dpkg >/dev/null 2>&1; then
-      if ! dpkg -s openprinting-ppds > /dev/null 2>&1; then
-        printerror "You must have the correct printer drivers installed, please run:"
-        printerror "  sudo apt-get install openprinting-ppds"
-        printerror "first, or use the generic driver instead."
-        exit 1
-      else 
-        if [ "${Driver}" = "postscript" ]; then
-          DriverPath="openprinting-ppds:0/ppd/openprinting/Ricoh/PS/Ricoh-MP_C6003_PS.ppd"
-        else
-          DriverPath="openprinting-ppds:0/ppd/openprinting/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd"
+      # This should match Debian, Ubuntu and most if not all derivates that use dpkg as the primary package manager
+      if command -v dpkg >/dev/null 2>&1; then
+        if ! sudo dpkg -s openprinting-ppds > /dev/null 2>&1; then
+          printerror "You must have the correct printer drivers installed, please run:"
+          printerror "  sudo apt-get install openprinting-ppds"
+          printerror "first, or use the generic driver instead."
+          exit 1
+        else 
+          if [ "${Driver}" = "postscript" ]; then
+            DriverPath="openprinting-ppds:0/ppd/openprinting/Ricoh/PS/Ricoh-MP_C6003_PS.ppd"
+          else
+            DriverPath="openprinting-ppds:0/ppd/openprinting/Ricoh/PXL/Ricoh-MP_C6003_PXL.ppd"
+          fi
         fi
       fi
     fi
   fi
 fi
 
         fi
       fi
     fi
   fi
 fi
 
-echo "This script will add a new printer called ${PrintName}, connecting to the
-print server ${PrintServer} using your normal user name and
-password from NTNU.
-
-NOTE: Your credentials will be stored in plaintext in /etc/cups/printers.conf.
-This file us usually not readable for normal users, but still:
-Do not use this script on multi user systems!"
+echo "This script will add a new printer called ${QueueName}, connecting to the
+print server ${PrintServer} using your user name and password from NTNU."
 
 # Get username and password
 printf "User name: "
 
 # Get username and password
 printf "User name: "
-read Username
+read -r Username
 printf "Password: "
 Settings=$(stty -g)
 stty -echo
 printf "Password: "
 Settings=$(stty -g)
 stty -echo
-read Password
+read -r Password
 stty "${Settings}"
 
 echo ""
 
 # Some further tests for Linux systems
 stty "${Settings}"
 
 echo ""
 
 # Some further tests for Linux systems
-# TODO: Add similar tests for macOS
 if [ "${Uname}" = "linux" ]; then
 if [ "${Uname}" = "linux" ]; then
-  # Test for valid username and password if on Linux
+  # Test for valid username and password
   # Bonus: find out if the print share is actually available
   PrintServerIP=$(getent ahostsv4 ${PrintServer} | head -n 1 | cut -d " " -f 1)
   # Bonus: find out if the print share is actually available
   PrintServerIP=$(getent ahostsv4 ${PrintServer} | head -n 1 | cut -d " " -f 1)
-  smbclient -U "${Workgroup}/${Username}%${Password}" -L "//${PrintServer}" -I "${PrintServerIP}" > /dev/null 2>&1
-  if [ $? -ne 0 ]; then
+  if ! smbclient -U "${Workgroup}/${Username}%${Password}" -L "//${PrintServer}" -I "${PrintServerIP}" > /dev/null 2>&1; then
     printerror "User name or password incorrect, or no contact with the print server ${PrintServer}."
     exit 1
   fi
     printerror "User name or password incorrect, or no contact with the print server ${PrintServer}."
     exit 1
   fi
-  ShareFound=$(smbclient -U "${Workgroup}/${Username}%${Password}" -L "//${PrintServer}" -I "${PrintServerIP}" -g 2>/dev/null | grep ${PrintShare} | cut -d "|" -f 1)
+  ShareFound=$(smbclient -U "${Workgroup}/${Username}%${Password}" -L "//${PrintServer}" -I "${PrintServerIP}" -g 2>/dev/null | grep ${PrintFile} | cut -d "|" -f 1)
   if [ "${ShareFound}" != "Printer" ]; then
   if [ "${ShareFound}" != "Printer" ]; then
-    printerror "Could not find printer share called ${PrintShare} on the server" 
+    printerror "Could not find printer share called ${PrintFile} on the server" 
     printerror "This script must be broken or outdated. Please contact orakel@ntnu.no for further assistance."
     exit 1
   fi
 fi
 
     printerror "This script must be broken or outdated. Please contact orakel@ntnu.no for further assistance."
     exit 1
   fi
 fi
 
-# Finally we can add the printer
+# Similar tests for OSX
+if [ "${Uname}" = "darwin" ]; then
+  if ! smbutil view -A "//${Workgroup};${Username}:${Password}@${PrintServer}" > /dev/null 2>&1; then
+    printerror "User name or password incorrect, or no contact with the print server ${PrintServer}."
+    exit 1
+  fi
+  ShareFound=$(smbutil view "//${Workgroup};${Username}:${Password}@${PrintServer}" 2>/dev/null | grep ${PrintFile} | cut -d " " -f 1)
+  if [ "${ShareFound}" != "${PrintFile}" ]; then
+    printerror "Could not find printer share called ${PrintFile} on the server" 
+    printerror "This script must be broken or outdated. Please contact orakel@ntnu.no for further assistance."
+    exit 1
+  fi
+fi
+
+# Finally we can add the printer, let's remove any existing printer share with the same name first
+sudo lpadmin -x ${QueueName} > /dev/null 2>&1
 
 # The Linux way
 if [ "${Uname}" = "linux" ]; then
 
 # The Linux way
 if [ "${Uname}" = "linux" ]; then
-  lpadmin  -p ${PrintName} \
+  if [ "${Plaintext}" = "YES" ]; then
+    PrinterShare="smb://${Workgroup}/${Username}:${Password}@${PrintServer}/${PrintFile}"
+    AuthInfo="none"
+    echo -e "\nNOTE: Your credentials will be stored in plaintext in /etc/cups/printers.conf.\nThis is usually only necessary on headless systems or on systems that don't run a dbus-daemon and/or a keyring that can provide the org.freedesktop.secrets service.\nNeedless to say, this is not a good idea on multi-user systems.\n"
+  else
+    PrinterShare="smb://${Workgroup}/${PrintServer}/${PrintFile}"
+    AuthInfo="username,password"
+  fi
+  if ! sudo lpadmin  -p ${QueueName} \
    -D "FollowMe print queue at NTNU" \
    -D "FollowMe print queue at NTNU" \
-   -v "smb://${Username}:${Password}@${Workgroup}/${PrintServer}/${PrintShare}" \
+   -L "Many locations" \
+   -v "${PrinterShare}" \
    -m "${DriverPath}" \
    -m "${DriverPath}" \
-   -u allow:all -E
+   -o auth-info-required="$AuthInfo" \
+   -u allow:all -E; then
+    printerror "Could not connect to printer share. See above error for details."
+    exit 1
+  fi
+  if [ "${Plaintext}" != "YES" ]; then
+    # Add credentials to the keyring
+    if ! echo -n "${Password}" | secret-tool store \
+     --label "ipp://localhost:631/printers/$QueueName" \
+     uri "ipp://localhost:631/printers/${QueueName}" \
+     user "${Username}"; then
+      printerror "Could not store credentials to the keyring, see above error for details. A workaround can be to use the option --plaintext"
+    fi
+  fi
 fi
 
 # The OSX way
 if [ "${Uname}" = "darwin" ]; then
 fi
 
 # The OSX way
 if [ "${Uname}" = "darwin" ]; then
-  lpadmin -p ${PrintName} \
+  if ! sudo lpadmin -p ${QueueName} \
    -D "FollowMe print queue at NTNU" \
    -D "FollowMe print queue at NTNU" \
-   -v "smb://${Workgroup};${Username}:${Password}@${Workgroup}/${PrintServer}/${PrintShare}" \
+   -L "Many locations" \
+   -v "smb://${PrintServer}/${PrintFile}" \
    -m "${DriverPath}" \
    -m "${DriverPath}" \
-   -u allow:all -E
-fi
+   -o printer-is-shared=false -o printer-op-policy=authenticated \
+   -u allow:all -E; then
+    printerror "Could not connect to printer share. See above error for details."
+    exit 1
+  fi
 
 
-if [ $? -ne 0 ]; then
-  printerror "Could not connect to printer share. See above error for details."
-  exit 1
+  sudo cupsenable "${QueueName}"
+  sudo cupsaccept "${QueueName}"
+
+  # Add credentials to the keychain if they are missing
+  # Shamelessly stolen^W^WBorrowed from https://github.com/Orakeltjenesten/scripts/blob/33abfb353524f449f0bbdee27adb2f1f0a9756a2/print/ntnuprint-mac.sh
+  # TODO: Since we should have a known-good username and password at this stage it's unwise to re-use the existing credentials, can we simply drop the test?
+  if ! security find-internet-password -s ${PrintServer} >/dev/null 2>&1; then
+    security -v add-internet-password -a "${Workgroup}\\${Username}" -s ${PrintServer} \
+     -w "${Password}" -D "Network Password" -r "smb " -l "${QueueName}" \
+     -T /System/Library/CoreServices/NetAuthAgent.app -T 'group://NetAuth' \
+     -T /System/Library/CoreServices/NetAuthAgent.app/Contents/MacOS/NetAuthSysAgent >/dev/null 2>&1
+  fi
 fi
 
 # Set correct paper size and enable the duplexer option
 fi
 
 # Set correct paper size and enable the duplexer option
-lpadmin -p ${PrintName} -o PageSize=A4 -o Option1=True
-
-if [ $? -ne 0 ]; then
-  printerror "Could not set default options on the print queue ${PrintName}. See above error for details."
+if ! sudo lpadmin -p ${QueueName} -o PageSize=A4 -o Option1=True; then
+  printerror "Could not set default options on the print queue ${QueueName}. See above error for details."
   exit 1
 fi
 
 # Set as default
   exit 1
 fi
 
 # Set as default
-lpadmin -d ${PrintName}
-
-if [ $? -ne 0 ]; then
-  printerror "Could not set the print queue ${PrintName} as default printer. See above error for details."
+if ! sudo lpadmin -d ${QueueName}; then
+  printerror "Could not set the print queue ${QueueName} as default printer. See above error for details."
   exit 1
 fi
 
   exit 1
 fi
 
-echo "Printer successfully installed."
+echo "Printer successfully installed. You may need to restart cups for the changes to take effect."