2009-10-14

SSH over LPR

A couple weeks ago, somebody asked if it were possible to get printers from school to work through a local cups client (ala, just putting the print server in client.conf). Some google-fu landed me this script for making a cups backend that prints via ssh. Of course, like most things on the intarwebs, it almost does what I wanted it to do.

A little tweaking and I got the script to run on my laptop, using ssh-agent so that I don't have to have passwordless root keys in order to print anywhere (still need them for my fuse-sshfs/autofs hack, though). Since archlinux runs cups as daemon instead of root, the script needs an suid wrapper in order to work properly (daemon can't su to $user).

The instructions are basically the same as for the original script. Install (or install suid wrapper) to /usr/lib/cups/backend . Then restart cups and add the printer. Cups will not show the remote and local users, but they are stored and will work correctly.

Exit codes can be modified to make the "printer" respond differently based on various conditions. For example, `exit 3` causes the queue to be stopped if the print server is not responding.

#!/bin/sh

# SSH-LPR Backend

# The purpose of the back end is to send print jobs to a remote system
# through ssh and lpr on the remote side. It requires that the user who
# wishes to print have a key-based authentication set up for the server in
# question. The printer URI is sshlpr://[ruser[:luser]@]server/queue where
# ruser is the name of remote user if it is different from the local use
# name, luser is the local user account with the SSH key, if different
# from the user who actually printed, server is the host and queue is the
# print queue name as it would get passed to lpr -P queue.

# With no parameters, we need to tell CUPS what we are.
if [ $# -le 0 ]
then
        echo "network sshlpr \"Unknown\" \"LPR thorugh SSH\""
        exit 0
fi

HOME='/root'
export HOME

# If we get the correct number of arguments, as per:
#       $1=job-id $2=user $3=title $4=copies $5=options $6=[file]
[ $# -lt 5 -o $# -gt 6 ] && exit 1

# Parse URL
user=$2
localuser=$2

[ -z "$DEVICE_URI" ] && exit 1

server="`echo $DEVICE_URI | cut -f 3 -d /`"
printer="`echo $DEVICE_URI | cut -f 4 -d /`"
if echo $server | grep '@' > /dev/null 2> /dev/null
then
        user="`echo $server | cut -f 1 -d '@' `"
        server="`echo $server | cut -f 2 -d '@' `"
fi

if echo $user | grep ':' > /dev/null 2> /dev/null
then
        localuser="`echo $user | cut -f 1 -d ':' `"
        user="`echo $user | cut -f 2 -d ':' `"
fi

# sanitize input for title
title=`echo $3 | sed -e "s/'//g" -e 's/"//g'`

# find a running SSH_AGENT
for i in /tmp/ssh-*/agent.* ; do
        if [ -r $i ] ; then
                ssh_auth_old=$SSH_AUTH_SOCK
                SSH_AUTH_SOCK=$i
                export SSH_AUTH_SOCK
                lines=`ssh-add -l | wc -l`
                if [ $lines -eq 0 ] ; then
                        SSH_AUTH_SOCK=$ssh_auth_old
                        export SSH_AUTH_SOCK
                fi
        fi
done

echo "Using SSH_AUTH_SOCK of $SSH_AUTH_SOCK" >&2

LPR="/usr/bin/lpr -U ${user} -P ${printer} -J '${title}' -# $4"

/bin/ping -c 1 -W 1 $server >/dev/null 2>&1
if [ $? -ne 0 ] ; then
        echo "Host is down: $server"
        exit 3
fi

echo "Doing cat $6 | su $localuser -c \"ssh $user@$server \\\"$LPR\\\"\"" >&2

# Has CUPS given us a file in $6?
if [ -r "$6" ] ; then
        /bin/cat $6 | su $localuser -c "/usr/bin/ssh -q -o BatchMode=yes ${user}@${server} \"${LPR}\""
        if [ $? -eq 0 ] ; then exit 0; fi
        exit 3
else
        echo "Cannot read file: $6" >&2
        exit 2
fi

:wq

No comments:

Post a Comment