How to Log File Removals using Shell Script

Posted on 7:14 PM by Bharathvn

The basic idea of wrappers is that they live between an actual Unix command and the user, offering the user different and useful functionality not available with the actual command alone. In the case of this script, file deletions using the rm command will actually be logged in a separate log file without notifying the user.

The Code
#!/bin/sh
# logrm - Logs all file deletion requests unless the -s flag is used.

removelog="/var/log/remove.log"

if [ $# -eq 0 ] ; then
echo "Usage: $0 [-s] list of files or directories" >&2
exit 1
fi

if [ "$1" = "-s" ] ; then
# silent operation requested ... don't log
shift
else
echo "$(date): ${USER}: $@" >> $removelog
fi

/bin/rm "$@"

exit 0

Running the Script
Rather than give this script a name like logrm, a typical way to install a wrapper program is to rename the underlying program and then install the wrapper using the underlying program's old name. If you choose this route, make sure that the wrapper invokes the newly renamed program, not itself. For example, if you rename /bin/rm to /bin/rm.old and name this script /bin/rm, the last few lines of the script will need to be changed so that it invokes /bin/rm.old, not itself!

You can also use an alias to have this script wrap a standard call to rm:

alias rm=logrm

In either case, you will, of course, need write and execute access to /var/log, which might not be the default configuration on your particular Unix or Mac OS X system.

The Results
Let's create a few files to delete, delete them, and then examine the remove log:

$ touch unused.file ciao.c /tmp/junkit
$ logrm unused.file /tmp/junkit
$ logrm ciao.c
$ cat /var/log/remove.log
Thu Jul 3 11:32:05 MDT 2003: susan: /tmp/central.log
Fri Jul 4 14:25:11 MDT 2003: taylor: unused.file /tmp/junkit
Fri Jul 4 14:25:14 MDT 2003: taylor: ciao.c

Aha! Notice that on the previous day user susan deleted the file /tmp/central.log.

Hacking the Script
There's a potential log file ownership permission problem here too. Either the remove.log file is writable by all, in which case a user could clear its contents out with a command like cat /dev/null > /var/log/remove.log, or it isn't writable by all, in which case the script can't log the events. You could use a setuid permission so that the script runs with the same permissions as the log file, but there are two problems with this. First, it's a really bad idea! Never run shell scripts under setuid! Second, if that's not enough of a reason, you could get into a situation where the users have permission to delete their files but the script doesn't, and because the effective uid set with the setuid would be inherited by the rm command itself, things would break and there would be great confusion when users couldn't remove their own files, even when they check and see that they own the files in question.

Two other possible solutions to this problem are worth mentioning. First, if you have an ext2 or ext3 file system (probably Linux), you can use the chattr command to set a specific append-only file permission on the log file and then leave it writable to all without any danger. Second, you can write the log messages to syslog, using the helpful logger command. To log the rm commands with logger is straightforward:

logger -t logrm "${USER:-LOGNAME}: $*"

This adds an entry to the syslog data stream (untouchable by regular users) that is tagged with logrm, the username, and the command specified.

Syslog nuances to watch for If you opt for this approach, you'll want to check syslogd(8) to ensure that your configuration doesn't discard user.notice priority log events (it's almost always specified in the /etc/ syslogd.conf file).