Last updated October 29, 2012. Created by OnkelTem on October 29, 2012.
Log in to edit this page.
Theory
You can grab enough ACLs theory from http://users.suse.com/~agruen/acl/linux-acls/online/. Or just google for "Linux ACL".
Script for setting permissions
Ok, I'm gonna share my script which I use to set permissions for Drupal websites. It is ready-for-use just for me, not for your. It's not a production-ready thing, you should understand what script does and probably edit it to accommodate your needs.
The script is called setacl and is supposed to be located in same directory where you have your website's root (DOCUMENT_ROOT) - let's refer to it as to project root. The script is using simple configuration file project.conf so let's start from it.
Configuration file: project.conf
I'm using many scripts for site and database management, for this reason there are lines which are not used by the setacl script but I won't remove them for now to provide you the whole picture.
SITE=MySite
DATABASE=mysite
PREFIX=ms_
USER=root
HOST=localhost
HOSTCODE=LO
PASSWORD=password
ACL_SETS="DEV WEB"
# Developers
ACL_DEV_USERS="onkeltem"
ACL_DEV_GROUPS="devteam"
ACL_DEV_WRITES="."
# Web server
ACL_WEB_USERS="www-data"
# path:number notation is used to specify exact depth for a path.
ACL_WEB_NOACCESS=".:1"
ACL_WEB_READS="www .:0"
ACL_WEB_WRITES="www/sites/default/files"The subject of our interest are the variables which names start from "ACL_". Since bash doesn't support associative arrays I have to keep meta-data right into variable names.
ACL_SETS="DEV WEB"
This defines a list of suffixes each one corresponds to some specific permission rules. Here are defined two sets: for developers and for web server.
ACL_DEV_USERS="onkeltem"ACL_DEV_GROUPS="devteam"
These two lines defines who belongs to DEV set. Supported both users and groups.
ACL_DEV_WRITES="."
This line tells that developers have write access to any file and any directory from the current one down to the deepest recursively.
More illustrative is another part, for the WEB set:
ACL_WEB_NOACCESS=".:1"
This will revoke any access to any directory or file in the project root. So you can safely keep any files or directories apart from 'www' directory itself in the project root: scripts, database backups, additional dev directories etc. Recursion now is limited by specifying exact depth of operation: 1.
ACL_WEB_READS="www .:0"
This list consist of two pieces separated by white-space: www and .:0. The former will grant read permissions from the site's root recursively down. The latter will affect only current directory and no files - i.e. project root directory for ":0" spec is used, meaning exact depth of 0.
ACL_WEB_WRITES="www/sites/default/files"
As with DEV's write spec, this grants right access for the files and directories starting from www/sites/default/files.
That's it!
The script
The script runs fine w/o root privileges for newly uploaded websites when you own all the files and thus have full access to them. So upon the first run it will set permissions according to the configuration. All directories acquire "inheritance" (default, -d) flag for any new file or directory will inherit permissions and you don't need actually to rerun the script later. If you do though, you will probably get a bunch of "Operation not permitted" error messages. This doesn't mean that script completely failed - it just can't set permissions on files you are not owning - those are created by web server inside sites/default/files.
Now the script:
#!/bin/bash
. ./project.conf
OPTIONS=$1
ROOT=`readlink -f .`/
function msg {
test "$OPTIONS" = '-q' && echo -n || echo -e "\e[01;34m"$1"\e[00m"
}
function exec {
cmd=$1
IFS='%' && msg " executing $cmd" && unset IFS
$cmd
}
msg 'set: ALL'
# Remove all extended ACLs
exec "setfacl -R -b $ROOT"
# Set correct permissions on directories and files
exec "find "`readlink -f $ROOT`" -type d -exec chmod 751 {} +"
exec "find "`readlink -f $ROOT`" -type f ! -perm -u=x -exec chmod 640 {} +"
exec "find "`readlink -f $ROOT`" -type f -perm -u=x -exec chmod 751 {} +"
exec "find "`readlink -f $ROOT`" -type d -exec chmod g-s {} +"
exec "find "`readlink -f $ROOT`" -type f -exec chmod g-s {} +"
function grant {
if [ "$4" == "read" ]; then
dperm="r-x"
fperm="r"
fpermx="r-x"
else
if [ "$4" == "write" ]; then
dperm="rwx"
fperm="rw"
fpermx="rwx"
else
dperm="--x"
fperm="---"
fpermx="--x"
fi
fi
if [ "$2" == "group" ]; then
who="g"
else
if [ "$2" == "user" ]; then
who="u"
else
exit
fi
fi
IFS='%' && msg " granting ${4:-noaccess} on "`readlink -f $ROOT${1}`" to $3 $2" && unset IFS
# Existing directories
path=${1%:*}
depth=${1#*:}
[[ ! $path == $depth ]] && depth_spec="-mindepth $depth -maxdepth $depth" || depth_spec=""
mkdir -p $ROOT${path}
exec "find "`readlink -f $ROOT${path}`" $depth_spec -type d -exec setfacl -m ${who}:$3:${dperm} {} +"
# Existing non executable files
exec "find "`readlink -f $ROOT${path}`" $depth_spec -type f ! -perm -u=x -exec setfacl -m ${who}:$3:${fperm} {} +"
# Existing executable files
exec "find "`readlink -f $ROOT${path}`" $depth_spec -type f -perm -u=x -exec setfacl -m ${who}:$3:${fpermx} {} +"
# New directories and files
[[ $path == $depth ]] && exec "find "`readlink -f $ROOT${path}`" $depth_spec -type d -exec setfacl -d -m ${who}:$3:${dperm} {} +"
}
for s in $ACL_SETS
do
msg "set: ${s}"
U=ACL_${s}_USERS
G=ACL_${s}_GROUPS
N=ACL_${s}_NOACCESS
R=ACL_${s}_READS
W=ACL_${s}_WRITES
for u in ${!U}
do
IFS='%' && msg ' user:' ${u} && unset IFS
for d in ${!N}; do grant $d "user" $u ""; done
for d in ${!R}; do grant $d "user" $u "read"; done
for d in ${!W}; do grant $d "user" $u "write"; done
done
for g in ${!G}
do
IFS='%' && msg ' group:' ${g} && unset IFS
for d in ${!N}; do grant $d "group" $g ""; done
for d in ${!R}; do grant $d "group" $g "read"; done
for d in ${!W}; do grant $d "group" $g "write"; done
done
doneIf you still need to run the script to reset everything on an existing website, then you will either need to run it under root (easiest way) or own the files from the beginning. For example you can:
- add group spec to the configuration:
ACL_WEB_GROUPS="www-data" - add your user account to
www-datagroup - change default permissions which are now hardcoded in the script (lines 24-28)
- change
umaskfor web server process to0002or something.