For writing tests for GVFS (current tests, proposed improvements) I want to run Samba as normal user, so that we can test gvfs’ smb backend without root privileges and thus can run them safely and conveniently in a “make check” environment for developers and in JHBuild for continuous integration testing. Before these tests could only run under gvfs-testbed, which needs root.
Unlike other servers such as ssh or ftp, this turned out surprisingly non-obvious and hard, so I want to document it in this blog post for posterity’s benefit.
Running the server
Running smbd
itself is mainly an exercise of figuring out all the options that you need to set; Alex Larsson and I had some fun figuring out all the quirks and hiccups that happen between Ubuntu’s and Fedora’s packaging and 3.6 vs. 4.0, but finally arrived at something working.
First, you need to create an empty directory where smbd can put all its databases and state files in. For tests you would use mkdtemp()
, but for easier reading I just assume mkdir /tmp/samba
here.
The main knowledge is in the Samba configuration file, let’s call it /tmp/smb.conf
:
[global] workgroup = TESTGROUP interfaces = lo 127.0.0.0/8 smb ports = 1445 log level = 2 map to guest = Bad User passdb backend = smbpasswd smb passwd file = /tmp/smbpasswd lock directory = /tmp/samba state directory = /tmp/samba cache directory = /tmp/samba pid directory = /tmp/samba private dir = /tmp/samba ncalrpc dir = /tmp/samba [public] path = /tmp/public guest ok = yes [private] path = /tmp/private read only = no
For running this as a normal user you need to set a port > 1024, so this uses 1445 to resemble the original (privileged) port 445. The map to guest
line makes anonymous logins work on Fedora/Samba 4.0 (I’m not sure whether it’s a distribution or a version issue). Don’t ask about “dir” vs. “directory”, that’s an inconsistency in Samba; with above names it works on both 3.6 and 4.0.
We use the old “smbpasswd” backend as shipping large tdb files is usually too inconvenient and brittle for test suites. I created an smbpasswd file by running smbpasswd
on a “real” Samba installation, and then using pdbedit
to convert it to a smbpasswd file:
sudo smbpasswd -a martin sudo pdbedit -i tdbsam:/var/lib/samba/passdb.tdb -e smbpasswd:/tmp/smbpasswd
The result for password “foo” is
myuser:0:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:AC8E657F83DF82BEEA5D43BDAF7800CC:[U ]:LCT-507C14C7:
which you are welcome to copy&paste (you can replace “myuser” with any valid user name, of course).
This also defines two shares, one public, one authenticated. You need to create the directories and populate them a bit:
mkdir /tmp/public /tmp/private echo hello > /tmp/public/hello.txt echo secret > /tmp/private/myfile.txt
Now you can run the server with
smbd -iFS -s /tmp/smb.conf
The main problem with this approach is that smbd exits (“Server exit (failed to receive smb request)”) after a client terminates, so you need to write your tests in a way to only run one connection/request per test, or to start smbd in a loop.
Running the client
If you merely use the smbclient
command line tool, this is rather simple: It has a -p
option for specifying the port:
$ smbclient -p 1445 //localhost/private Enter martin's password: [enter "foo" here] Domain=[TESTGROUP] OS=[Unix] Server=[Samba 3.6.6] smb: \> dir . D 0 Wed Oct 17 08:28:23 2012 .. D 0 Wed Oct 17 08:31:24 2012 myfile.txt 7 Wed Oct 17 08:28:23 2012
In the case of gvfs it wasn’t so simple, however. Surprisingly, libsmbclient does not have an API to set the port, it always assumes 445. smbclient itself uses some internal “libcli” API which does have a way to change the port, but it’s not exposed through libsmbclient. However, Alex and I found some mailing list posts (1, 2) that mention $LIBSMB_PROG
, and it’s also mentioned in smbclient’s manpage. It doesn’t quite work as advertised in the second ML post (you can’t set it to smbd, smbd apparently doesn’t speak the socket protocol over stdin/stdout), and it’s not being used anywhere in the current Samba sources, but what does work is to use good old netcat:
export LIBSMB_PROG="nc localhost 1445"
with that, you can use smbclient or any program using libsmbclient to talk to our test smb server running as user.