Operation not permitted: Sticky and SETGID

1. User “foo” creates a directory with group read-write and sticky, without setgid

[foo@localhost ~]$ mkdir -p /tmp/test_sticky/test_setgid/{sub1,sub2,sub3}
[foo@localhost ~]$ chmod 3775 /tmp/test_sticky

2. User “foo” then creates a group read-write, setgid, non-sticky directory structure with few files underneath.

[foo@localhost ~]$ chmod 2775 /tmp/test_sticky/test_setgid
[foo@localhost ~]$ find /tmp/test_sticky/test_setgid -type d -exec chmod 775 "{}" \;
[foo@localhost ~]$ touch /tmp/test_sticky/test_setgid/{sub1/file1,sub2/file2,sub3/file3}

3. The resulting structure looks like this:

[foo@localhost ~]$ find /tmp/test_sticky -printf "%#m:%M:%u:%g:%p\n"|sort -n
0644:-rw-r--r--:foo:shared:/tmp/test_sticky/test_setgid/sub1/file1
0644:-rw-r--r--:foo:shared:/tmp/test_sticky/test_setgid/sub2/file2
0644:-rw-r--r--:foo:shared:/tmp/test_sticky/test_setgid/sub3/file3
02775:drwxrwsr-x:foo:shared:/tmp/test_sticky/test_setgid
02775:drwxrwsr-x:foo:shared:/tmp/test_sticky/test_setgid/sub1
02775:drwxrwsr-x:foo:shared:/tmp/test_sticky/test_setgid/sub2
02775:drwxrwsr-x:foo:shared:/tmp/test_sticky/test_setgid/sub3
03775:drwxrwsr-t:foo:shared:/tmp/test_sticky

4. User “bar” attempts to remove /tmp/test_sticky/test_setgid:

[bar@localhost ~]$ rm -rfv /tmp/test_sticky/test_setgid
removed `/tmp/test_sticky/test_setgid/sub3/file3'
removed directory: `/tmp/test_sticky/test_setgid/sub3'
removed `/tmp/test_sticky/test_setgid/sub2/file2'
removed directory: `/tmp/test_sticky/test_setgid/sub2'
removed `/tmp/test_sticky/test_setgid/sub1/file1'
removed directory: `/tmp/test_sticky/test_setgid/sub1'
rm: cannot remove `/tmp/test_sticky/test_setgid': Operation not permitted

The sticky bit set by “foo” on /tmp/test_sticky prevented “bar” from deleting
/tmp/test_sticky/test_setgid, effectively overriding the setgid permissions.

5. Deleting the test_setgid directory as “bar” without the sticky bit enabled
[ As "foo", drop the permissions back to setgid only: chmod 02775 /tmp/test_sticky ]

[bar@localhost ~]$ rm -rfv /tmp/test_sticky/test_setgid
removed directory: `/tmp/test_sticky/test_setgid'

Launch Aquamacs from within a shell

Problem

  • Opening Aquamacs from the shell (/Applications/Aquamacs.app/Contents/MacOS/Aquamacs) throws many deprecation warnings.
  • Multiple instances of Aquamacs are appended to the dock when launched, and it is annoying.

Solution

  1. Open Aquamacs.app
  2. Click “Tools
  3. Click “Install Command Line Tools

Resolution

The path to Aquamacs after installing the command line tool package is /usr/bin/aquamacs

Remote filesystems and mlocate

Have you ever worked in a clustered environment that provided remote home directories?  Furthermore, have you ever been annoyed by the fact mlocate does not descend into these remote file systems by default?  Me too.  I’ve written two small BASH scripts to address this problem.

updatedb_extern

#!/bin/bash

# Edit DEST to point to a local directory you have write access to
DEST=/path/to/local/database/directory

#Don't edit below this line (no point)
EXTERN=( "$@" )
DATABASES=()

#Did we receive any paths to process?
if [ -z "$EXTERN" ] ; then
	echo "No path(s) specified."
	exit 1
fi

#Simple adapation logic to ensure we will have a writable data area
if [ ! -d "$DEST" ] ; then
	mkdir -p $DEST 2>/dev/null
	if [ $? != 0 ] ; then
		DEST=/var/tmp/mlocate
		mkdir -p $DEST 2>/dev/null
		if [ $? != 0 ] ; then
			echo "No suitable path to store locate database."
			exit $?
		fi
	fi
fi

#Generate database names based on external path
#Example: /home/myuser becomes _home_myuser.db
for path in "${EXTERN[@]}"
do
	database=$(echo $path | sed -e "s|/|_|g")
	DATABASES[${#DATABASES[*]}]="$DEST/${database}.db"
done

#For each external path generate an mlocate database
MAX=${#EXTERN[@]}
for (( i=0; i<$MAX; i++))
do
	i_fake=$(( i + 1 ))
	path=${EXTERN[$i]}
	dbpath=${DATABASES[$i]}
	echo "[$(echo $(( $i_fake * 100 / $MAX )))%] $path -> $dbpath"
	updatedb -l 0 -o $dbpath -U $path
done
echo

The developers of mlocate were nice enough to implement the environment variable, LOCATE_PATH, to extend the database search path.  We’re going to use it to our advantage with the following script.

updatedb_extern_setup

#!/bin/bash

DEST=$1
if [ -z "$DEST" ] ; then
	echo "No database path specified."
	exit 1
fi

for db in $DEST/*.db
do
	DELIM=":"
	if [ -z "$LOCATE_PATH" ] ; then
		DELIM=
	fi

	LOCATE_PATH=${LOCATE_PATH}${DELIM}${db}
done
echo "$LOCATE_PATH"

 

Example Usage

In your ~/.bashrc or ~/.bash_profile (or ~/.profile):

export LOCATE_PATH=`update_extern_setup /path/to/local/database/directory`

In your crontab (e.g. crontab -e):

* 2 * * * updatedb_extern /home/username /some/remote/path

Manually:
updatedb_extern /home/username /some/remote/path