Tuesday, March 26, 2013

Sharing Directories with Windows, Linux and Mac OS X

Yesterday I posted about setting up Netatalk so I could see some directories on my Raspberry Pi from a Mac OS X machine.

To recap, my goal was to be able to use a remote debugger and IDE on the Mac to develop code running on the Raspberry Pi. The IDE I use is Komodo.  It is proprietary application but I can't bring myself to relinquish its features.

Whilst Komodo can remotely debug quite happily without any integration with the remote system, to take advantage of many of its features  and persist your settings across invocations of the remote code it needs access to the code source files. For the Mac, the netatalk setup gave me that.  Next I wanted to be able to access the same Raspberry filesystem from Windows and Linux.

Samba is an implementation of CIFS (Common Internet File System), a network sharing protocol commonly used by MS Windows operating systems to share files and resources. We can use it to share some directories on our Raspberry Pi so that they look like Windows shares to the other machines on our network. The advantage of Samba is that in addition to our Windows machines, the Mac OS X and Linux machines on our network will be able to access the shares without difficulty. We can provide for all three client types with a single service running on the Raspberry Pi.

Installing Samba on the Raspberry Pi

On the Raspberry Pi we install the Samba packages.

sudo apt-get update
sudo apt-get install samba samba-common-bin

The configuration file for Samba is at /etc/samba/smb.conf. We won't edit this directly. Firstly, we want to ensure we keep a copy of the original. Assuming you are running as user pi on the Raspberry Pi:

cp /etc/samba/smb.conf /home/pi/smb.conf.orig

Samba provides a utility that will check your configuration file, and output the result stripped of comments and default settings. We will use that to produce our configuration file from a master that we shall edit.

Create the master file for editing:

nano /home/pi/sambamaster.conf

The following is my master config file that you may paste and edit. You will need to edit it.

[global]
# Change to your workgroup name
  workgroup    = WORKGROUP

# Change to your chosen unique name
  netbios name = RASPMODELB

  server string = %h server
  map to guest = Bad User
  obey pam restrictions = Yes
  pam password change = Yes
  passwd program = /usr/bin/passwd %u

# The 'passwd' chat entry should be on a single line

  passwd chat = *Enter\snew\s*\spassword:* %n\n
        *Retype\snew\s*\spassword:* %n\n
        *password\supdated\ssuccessfully* .

    unix password sync = Yes
  syslog = 0
  log file = /var/log/samba/log.%m
  max log size = 1000
  dns proxy = No
  usershare allow guests = Yes
  panic action = /usr/share/samba/panic-action %d
  idmap config * : backend = tdb
    server min protocol = SMB2

[piraspmodelb]
    comment = Pi Home Directory
    path = /home/pi
  valid users = pi
  read only = No
  create mask = 0644
  browseable = Yes

[raspberryusbdrive]
  comment = Raspberry Pi USB Drive
  path = /media/hdd/pi
  valid users = pi
  read only = No
  create mask = 0644
    browseable = Yes

This setup is good for any network where you are not running a Windows Domain Controller. I have shared two folders, the user pi home directory and the 'pi' subdirectory of a usb hard drive I have connected to this Raspberry Pi. The shares will appear as 'piraspmodelb' and 'raspberryusbdrive'.  Obviously you may only want to share the 'pi' user home directory so you will only have one share section.

Samba offers the facility to automatically share home directories to logged in users under the config setting '[homes]' in the conf file. I did not want this as the share will be called after the user name (in my setup 'pi') and some clients (Mac OS X) will auto-mount this under the share name (/Volumes/pi). If I have a second Raspberry Pi and I use the same setup, then the home directory for user 'pi' on  that Raspberry Pi will be mounted as /Volumes/pi-1. The problem with this is that the assignment of the names is not stored between invocations. So the next time I reboot my Mac /Volumes/pi and /Volumes/pi-1 may point to different things depending on which one I access first.

If you would prefer to use the standard Samba [homes] share for user home directories you can use this link to a simple smb configuration example.

I chose the name 'piraspmodelb' as I'm currently the lucky owner of two Raspberries, a Model A and a Model B so I'm easily aware of whose home directory on which Pi I'm pointing at.

Note that I made both shares 'browseable'. This simply means they will 'appear' to network browsers that have not logged in as a particular user yet but has no effect on whether the files in the share can be viewed. You may need at least one share to be 'browseable' as some client implementations fall over without this.

After you have saved the file and exited 'nano' you can test the syntax and overwrite the actual configuration at the same time.

sudo sh -c 'testparm -s /home/pi/sambamaster.conf  >/etc/samba/smb.conf'

You might have expected to be able to do:
    testparm -s /home/pi/sambamaster.conf  >/etc/samba/smb.conf
but you cannot. The command redirection  '>' would be applied by your current user shell to the output of 'sudo' and you don't have permissions to write to /etc/samba/smb.conf. We have to call the 'sh' shell command with sudo and pass the whole command we want to run wrapped in quotes as the -c parameter.

As part of its integration with Windows networks, Samba can synchronise changes in the Windows access passwords with the unix passwords of users on the Raspberry Pi. We probably don't care too much about that for this setup, but we do nevertheless have to setup our Samba password. Assuming you are using user 'pi':

sudo smbpasswd -a pi

You will be prompted for your pi user password, which if you have not changed from the default will still be 'raspberry'.

When that's complete we can restart the Samba services on the Raspberry Pi:

sudo /etc/init.d/samba restart

Our shares should be visible to client machines on our network.

Connecting to Shares from Mac OS X

Open Finder and from the menu choose

Go -> Connect to Server

In my case I gave the Raspberry a netbios name of 'raspmodelb' so the server I want to connect to is

smb://raspmodelb


When connecting your user and password will be requested which in my case remains 'pi' and 'raspberry'. I select both the available shares to mount ( in my case 'piraspmodelb' and 'raspberryusbdrive' as defined in my smb.conf). The shares are now both browseable in Finder under 'raspmodelb'.



On the filesystem the shares are mounted as:

/Volumes/praspmodelb
/Volumes/raspberryusbdrive

Connecting to Shares from Windows

In Explorer type the netbios name of your Raspberry ( \\raspmodelb for my example ) in the address bar and press enter. This should display your shares.






It is my preference to map network drives for each of the shares. Right click on the share name and choose 'Map Network Drive.'. Remember to select 'Connect using a different user name' in the resulting dialog and enter your pi username and password.

Connecting to Shares from Linux

For Linux we'll mount the shares as part of our file system. My tests for this were done using Ubuntu 12.04 which seemed to have everything necessary installed by default. On other systems, the commands will be the same but you may have to install packages to support CIFS.

For the shares we created on the Raspberry Pi we'll need two mount points. In my case I simply named the mount points after the share names, but this isn't a requirement. You may choose whatever names you wish.

sudo mkdir /media/piraspmodelb
sudo mkdir /media/raspberryusbdrive

Then we mount the drives. I have found that this works best without problems if the Raspberry Pi is referenced by IP address. Get the IP address of your Raspberry using the command 'ifconfig' on the raspberry. Unless you have some custom setup you want the IP address of eth0. For this example we'll use an address of 192.168.0.5 for the Raspberry Pi.

On your Linux client:

sudo mount -t cifs //192.168.0.5/piraspmodelb   \
        /media/piraspmodelb -o user=pi,password=raspberry


sudo mount -t cifs //192.168.0.5/raspberryusbdrive  \
        /media/raspberryusbdrive -o user=pi,password=raspberry


This may be all that you will need to get a working setup but it relies on a coincidental match between the numeric uid of your user on the Linux client and the numeric uid of the 'pi' user on your Raspberry.

On the Raspbian Wheezy, the user 'pi' has the numeric uid 1000 and group gid 1000. For many users with their own personal installations of a Linux distribution the user they created when first installing the distribution and continue to use as a general login also has a uid of 1000 and a gid of 1000. So when the CIFS client is mapping the ids as a user with uid and gid 1000 exists on both systems, all works well.

If however your login user on your Linux Client doesn't have the uid and gid 1000, but some user on your system does, then all the files in the 'pi' home directory on your Raspberry that you mount on the Linux Client will appear to belong to user 1000 on your Linux Client - which is not your current login user. You will be restricted according to the permissions on each file and directory but as they likely will all belong to user 1000, you won't have write access to anything.

You can overcome this issue by specifying a numeric uid and gid when mounting the Samba share. If the login user you want to have read / write access to the mounted files has a uid of 1002 and a gid of 1003 then you would mount with:


sudo mount -t cifs //192.168.0.5/piraspmodelb   \
    /media/piraspmodelb                         \
    -o user=pi,password=raspberry,uid=1002,gid=1003


and all should work OK.

It is possible to alter your /etc/fstab on the Linux client so that the Raspberry Pi shares are mounted automatically. I don't do this because I don't like putting entries in fstab for devices that are often not present - and my Raspberry Pi is often powered off while I mess with circuitry.

I don't type the above out everytime either though.  A couple of bash scripts do the job for me:

mountraspberry.sh
#!/bin/sh

mount -t cifs //192.168.0.5/piraspmodelb \
    /media/piraspmodelb \
    -o user=pi,password=$1



mount -t cifs //192.168.0.5/raspberryusbdrive \
    /media/raspberryusbdrive \
    -o user=pi,password=$1


umountraspberry.sh
#!/bin/sh
umount -l /media/piraspmodelb
umount -l /media/raspberryusbdrive

called as

sudo ./mountraspberry.sh raspberry

sudo ./umountraspberry.sh