There are many cases in which you want to share files with someone “on the outside.” While e-mail attachments can be useful, when the file sizes start to get large, it becomes more and more problematic. Of course, if you only want to share files out, there’s the simple method of setting up a web server. But what if you want to receive files from others? That’s when it gets more complicated. One option is to find code for a file uploader that runs on a website, but that’s a bit heavy. What if you just want to receive a few large (or many small) files from a friend. Perhaps you’re providing an off-site backup, or you really want to see the 15,000 pictures they took on their recent trip to Conway, Arkansas. Either way, there’s a simple way to set up a place for friends to drop off your files, without having to set up a separate account for them, and without having to use the insecure File Transfer Protocol (FTP).
The first step is to create a generic user account that the outsiders will use. In this case, we assume that you don’t want this account to have shell access in order to run commands, so we’ll use /sbin/nologin as the shell. We’ll call the user ‘rsyncft’ (for “rsync file transfer”, although you could use whatever you want) and put the home directory in /var (again, you can put it wherever it makes sense for you). When it’s all put together. the command to add the user will look something like this:
useradd -m -c "rsync user" -N -d /var/rsyncft -s /sbin/nologin rsyncft
After you’ve added the user, the next step is to add yourself to the ‘rsyncft’ group you’ve created. This step is optional, but it will make it easier for you to get files in and out of the directory. (See the sidebar about group membership for more discussion on this topic). Next, you need to make sure you’ve got the lim_rsync script. I got this from some colleagues and have shared it on a previous post, but here it is again:
#!/bin/bash PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" TERM='vt100' # Make sure a command is specified (e.g. we're not trying to actually log in) if [[ $SSH_ORIGINAL_COMMAND == "" ]]; then exit 1 fi # Extract the first three bits of the command TEST_COMMAND=`echo $SSH_ORIGINAL_COMMAND | awk -F" " '{ print $1 " " $2 }'` # If rsync is called with "--server --sender", it means somebody is trying # to remotely copy files from us. Allow this. Deny all others. if [[ $TEST_COMMAND == "rsync --server" ]] || [[ $TEST_COMMAND == "/usr/local/bin/rsync --server" ]]; then exec $SSH_ORIGINAL_COMMAND else exit 2 fi
The script should work on both Linux and Solaris. I put it in /usr/local/bin, but you can put it anywhere you want, provided the rsyncft account can run it (but not write to it!) The point of this script is to check to see if the connection is an rsync connection or not. So how do we do this? Well, the last step is to add your friend’s SSH public key (if you’re not sure what I’m talking about, see this post from the Standalone Sysadmin blog). To do this, you’ll need to create the file ~rsyncft/.ssh/authorized_keys (you may need to create the .ssh directory, too) to include
command="/usr/local/bin/lim_rsync",no-pty,no-agent-forwarding,no-X11-forwarding,no-port-forwarding
Followed by the public key contents. If you know where the connections will be coming from, you can further secure the key by including a from= option (e.g. from=”*.myemployer.com” or from=”192.168.1.10″).
That’s it for the setup, your friends can now copy files into your computer. If you need to have multiple people connect, you can just add more keys to the authorized_keys file. By playing with the directory permissions, you can also make sure that files can be read or only written, depending on what it is you’re trying to accomplish. The people trying to connect to you will need to use SSH to make the rsync connection, like this:
rsync -e "ssh" file_to_copy rsyncft@your.computer.net:/var/rsyncft
Of course ‘your.computer.net’ should be replaced with the DNS name or IP address of your computer, and you’re free to use other options to rsync to modify the behavior. Now what if you want potentially anonymous users to be able to give you files? Perhaps you have some kind of scanner that runs on unmanaged machines in your department, and you need to collect the output. In that case, you can just create an SSH key that has no passphrase and include the public key in rsyncft’s authorized_keys file and add the location of the private key to your ssh command:
rsync -e "ssh -i /path/to/private_key" file_to_copy rsyncft@your.computer.net:/var/rsyncft
Sidebar: Being smart about group membership
When I wrote the first draft of this post, I suggested adding rsyncft to a group that you are a member of, for example “users”. Fortunately, I realized before I published that this is a Very Bad Idea™. If you were to do it this way, any group-writable files owned by this group could be modified. This is a really terrible security risk. A better alternative is to let useradd create a new group, and then add yourself to it. Then only the files that you want to be available are. A much heavier option would be to run this in a VM so that the outside user has no way to get to your files. This is more secure, but overkill for most users, and a bit more difficult to setup (not to mention more of a system overhead).