I wasn't sure if I should post this in a programming forum or this one, but I figured, since I wrote it as a utility for my sftp server, that I would just stick it here. Apologies if this is the wrong forum. If so, could a moderator please move it to a more appropriate one? Thank you.
So anyhow, here's the deal. I have a Pi 3B+ running as a small sftp server for family members and kept having issues with ownership and permissions. Basically, I decided that I needed a way to force new items in any given user's folder to have their ownership assigned to the user that owns the folder the item was put in, regardless of who put it there. It was *supposed* to be a quick and easy, down and dirty script. But as I learned what I needed to learn in bash in order to accomplish what I was trying to do, the script got more and more complex. I tried to account for anything I could think of, and then had to account for the things I didn't think of! So as I learned more about functions, and supporting command line options, and even a bit about text color formatting while writing this, it went from a quick and easy, down and dirty script to something far more polished that I'm actually quite happy with. Writing it has now encompassed the majority of my free time over this last week or so, and for the amount I've learned, I feel it was time well spent.
Now, considering I'm new to linux and bash, I wouldn't be surprised if some linux guru pops in and says "Oh, you only need to change file 'x' to make a folder's owner take ownership of anything you put in there". But I figured, even if that turns out to be the case, then hopefully the script would at least get some constructive criticism on the code itself. However, In my (admittedly) limited research, I simply could not find a way to force ownership of items placed into a user's folder. I figured, if it turns out there really isn't an easier, built-in way to do this, then maybe it could be useful to someone else who might also be in a similar situation where the group permissions weren't enough for a small sftp server for family or friends (or some other situation I haven't thought of.)
Script code can be found at: https://pastebin.com/qRSWAKp1Folder Owner Enforcer - Readme
Script code can be found at: https://pastebin.com/qRSWAKp1
I wrote this script for my own personal situation and chose to share it in case anyone else may find it useful.
Essentially it boils down to this - The script uses inotifywait to watch a defined base folder where all my sftp user folders are. When it notices a new file or folder added to a user's folder, it enforces that the new item's ownership goes to the user who owns the folder.
I wrote it because I have a small SFTP server with only a couple of users, but I kept having issues when putting files into a user's directory, as they were unable to be downloaded because the ownership and group of the file were set to my admin user's permissions. As such, I had to remind myself to change the ownership of anything I put into a user's folder every time or I would get the inevitable phone call or text telling me the file(s) couldn't be downloaded. Additionally, when a user uploaded something, if it went into a new folder, the folder was getting the correct ownership and permissions, but new files IN the new folder were not given the correct permissions I wanted for the group. As such, I was looking for a way to force a file or folder to change ownership to the user whose folder the item was put in, and enforcing the group and permissions regardless of how deep in a user's tree the new item was placed.
With this script, when I put something in someone's folder, they are given ownership, and the owner and group are set to the folder's owner and group, and the defined permissions are applied. This also works when one user puts a file into another user's folder, though that was really only an issue when, for example, user1 uploaded files into a new folder in user2's or user3's folder. The new folder had the correct owner, group and permissions, but the files IN the new folder did not have the right permissions (everything was read-only by other group members.) However, if user1 put the files directly into a user's base folder (not in a new sub-folder), all the permissions were applied correctly. Since I typically drop files directly into respective user folders from a mapped drive on my local network, anything I put into any user's folder would have the ownership and group set to my "admin" user, even though my admin user account is a member of the sftp group. Since I couldn't find another way to go about it, I decided to write this script to do it for me.
- inotify-tools must be installed on the system ("sudo apt-get install inotify-tools") if it's not already installed.
- the user used to create and invoke the script must have sudo privileges.
1.) Change to the /usr/local/bin folder
$ cd /usr/local/bin
2.) Create the file and open it in edit mode
$ sudo nano folder-owner-enforcer
3.) Paste the script into the open file
4.) Edit the USER-DEFINED VARIABLES section, setting the values you wish to use. Be aware the the LOGFILEPATH= value is set to /tmp by default. The /tmp directory is cleared on each system restart, so if you wish to maintain copies of the log files, you should point the LOGFILEPATH= value to the directory you wish to store your logs. If you decide to keep logs long-term, you should think of either offloading them to another system for archival purposes (if needed), or creating a cron job to run at a regular interval to clean up old, unwanted logs. For my setup, I don't need to retain any old logs, as I am usually only concerned with the last job run, so the /tmp folder works for my particular installation.
5.) Save (<ctrl>+o) and exit (<ctrl>+x) the nano editor
6.) Set the script to executable
$ sudo chmod +x folder-owner-enforcer
7.) Set up auto run using one of the following methods (do not use both)
Method 1 - (Using cron) This is the preferred method as it essentially runs invisibly to the user.
Method 2 - (Using LXDE GUI autostart) This should only be used with systems that boot directly into the GUI, otherwise the script won't automatically launch until the GUI is started manually, but it is useful if you boot into the GUI AND want a terminal window open logging the script actions. Note, however, that if you choose this method and you close the terminal window, the script will also exit and will need to be restarted manually to re-enable enforcement.
- 7_1a.) Launch the crontab editor
$ crontab -e
7_1b.) Add the following line to the bottom of the file, substituting the user you wish to run the script as. You MUST define a user that has sudo permission and you should NOT use the root user. The user defined in the command below is 'pi', so you would switch 'pi' to your user's name.
@reboot -u pi /usr/local/bin/folder-owner-enforcer
7_1c.) Save (<ctrl+o>) and exit (<ctrl+x>) the crontab editor.
- 7_2a.) The autorun location may be found in a different path on different distributions. This script was developed on Raspbian Stretch, so the paths reflected here are based on that platform. So on a Raspberry Pi running Raspbian Stretch, the path to edit autostart file is used in the example command, your path may be different. Using a terminal window (if the GUI is loaded) or at a regular CLI terminal, use the following command (substituting your path if neccesary)
$ sudo nano /etc/xdg/lxsession/LXDE-pi/autostart
7_2b.) Add the following line to the BOTTOM of the autostart file
7_2c.) Save (<ctrl>+o) and exit (<ctrl>+x) from the nano editor.
8.) Restart the system. When the system restarts, you can check if the script is running a couple of ways, depending on how you are auto starting it.
- If you boot straight into the GUI and you configured the LXDE autostart file method, you should see a terminal window open with the output from the script.
- If you boot into the CLI or are connecting remotely through SSH, you can issue the command "pidof inotifywait" (without the quotes.) If it returns a number, the script is running. Or you can use the -viewlog command line option (folder-owner-enforcer -viewlog) to view today's most recent log.
That's it. You really shouldn't have to touch it again once it's been configured correctly and set to automatically start on system restarts. While it is running, any items put into a user's folder will have their ownership set to the folder's owner and whatever permission mask you've defined for the script will be applied.