Friday, January 16, 2009

Remote Sane

Well, this is going to be my occasional blog on technical things. Hopefully I'll keep up with it, although I'm notoriously bad for doing so. In any case, here's the first one.

Recently Jen asked me to set-up scanning at home. We have an HP PSC 1510 All-in-One Printer/Scanner/Copier. It's currently hooked to my main router via USB. Now, I could easily have done all of the scanning from the main router via the "scanimage" command. But I really wanted to be able to scan from the other computers on my network, including Jen's Windows laptop. Enter saned, a small daemon that allows remote clients to access your scanner. However, getting this working had it's share of pitfalls.

Server Configuration

To start with, my main router is a Fedora 9 i386 box. The first order of business, of course, was to get scanning working locally. Luckily this is pretty easy nowadays; I just needed to install:

sane-backends-libs
sane-backends
libsane-hpaio

A quick "scanimage -L" shows that the scanner was detected, and a quick "scanimage > image.pnm" shows that it actually scans things. Great, the first part is over.

For the next part, I needed to setup saned. While saned is packaged with the sane-backends package, it is unfortunately not well integrated into the system. To get it working, I basically had to add it to xinetd, add the IP addresses I wanted to be able to scan from, add a new user, and finally make sure that when the device was plugged in, it got set to the appropriate user. Those steps are described below; note that I had a lot of help from the following web pages:

http://journal.newtoncomputing.co.uk/2008/07/network-sane-scanner-and-udev-permissions/
http://it.toolbox.com/blogs/locutus/the-scanner-the-network-and-a-saned-13396
http://penguin-breeder.org/sane/saned/

The first order of business is to get xinetd to start up saned. This is accomplished by adding a new file /etc/xinetd.d/saned, which looks like this:
service sane-port
{
socket_type = stream
server = /usr/sbin/saned
protocol = tcp
user = saned
group = saned
wait = no
disable = no
}
Then I did a quick restart of xinetd via "service xinetd restart". Next, we have to make sure that the "saned" user exists on the system; I did this with:
useradd -M -s /sbin/nologin -r -u 491 saned
Which creates a new user without a home directory, with no login shell, and with UID 491. With that in place, I was able to test what I have going so far with a quick "telnet 6566". If this doesn't spit any errors, then we at least have the daemon up and running.

With that in place, the daemon is running, but the problem is that the permissions on the USB device won't allow the saned user to actually access it. This is where things get tricky; in order for this to work, we really want to make sure the USB device is owned by saned *every* time it gets plugged in (or powered up). In modern Linux, including Fedora, the way to do this is with a custom udev rule. In my case, I created the file /etc/udev/rules.d/10-saned.rules, and put the following in:
ACTION=="add", SUBSYSTEM=="usb", NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0664", OWNER="saned", GROUP="saned"
What this says is that for any add action on the usb subsystem, change the owner to saned and the group to saned. Now, this rule isn't as refined as it could be; in particular, I probably only want this rule to run when the device being plugged in is in fact my USB scanner.

After adding in the above udev rule, I just had to power off my scanner, wait a few seconds, and then power it back up. Once I did that, I had to check that the /dev device was owned by the right user. To do that, I first had to find out which USB device my printer shows up as. That's easily accomplished by a quick "lsusb", and then looking for the Bus and Device number. In my case, that was Bus 002 and Device 009, so I just did a quick "ls -l /dev/bus/usb/002/009", and ensured that that /dev node was owned by saned:saned.

Finally, I had to add which clients I wanted to be allowed to scan over the network. To do that, I just added:
localhost
192.168.20.1/24
to /etc/sane.d/saned.conf.

Client Configuration

Now that I had the server all set up, it was time to try out my remote clients. The first thing to try was obviously my Linux laptop. This was actually a breeze; I just had to add the internal name of my server to /etc/sane.d/net.conf, and then xsane finds the scanner when it starts up.

Windows was a bit harder, but not much. Basically I went to http://sanetwain.ozuzo.net/ and downloaded the SaneTwain bridge there. After unzipping that package, I was able to start up the example executable and add my saned machine as a remote source, and it all worked!

No comments:

Post a Comment