dshahin has asked for the wisdom of the Perl Monks concerning the following question:

I have the need to syslog every command issued by a given set of users on a given set of systems for security auditing purposes. I want to provide a wrapper around the shell of their choice, and simply syslog the command before execution. The problem is that I need to transparently wrap any given shell, while still giving them any readline-esqe command editing abilities.

This program will be their login shell, to prevent escape to a non-logging shell. Are there any modules that can assist me, or is there a standard way of doing such a thing?

Replies are listed 'Best First'.
Re: wrapping any given shell
by Fastolfe (Vicar) on Feb 07, 2001 at 02:58 UTC
    You can always patch their shell to issue syslog calls for each command.

    Is there any reason you can't use some form of process accounting instead? This is supported by most any Unix, and is generally the accepted way of recording this type of information. Using syslog seems messy, and it won't catch cases where they execute commands via other commands. What's to stop them from executing /bin/sh on their own, completely circumventing your shell?

    If you go the "patch the shell" route, you'll also want to put in some logic to log only interactive sessions, else every shell script will get each line logged to syslog. There's a whole lot of things like this you'll want to be aware of. Process accounting seems like a much cleaner method.

      Can you do anything w/ ksh and .sh_history/command history? That's already built-in (guess you'd have to work to make it un-editable) so you'd just have to limit their access to /bin/ksh. Though ... can they change the .sh_history path? Are these potentially malevolent users or just a tracking business?

      a

        My impression is that if you want to track your users' movements, the users you generally want to track are capable of circumventing simple measures like this. Note that the shell only records what is typed into it. I can use special file-system flags to make it so that the history file can't be deleted, and can only be appended, but you're right: there's nothing to stop them from running their own shell, or writing a simple shell in Perl, completely circumventing this. The only way to "reliably" do this is to do it closer to the OS-level, which is why most Unix variants support process accounting here.

        The original poster should note that what he's trying to do is hardly novel or original, and most any major company's data center will have security policies requiring such accounting, and have generally thought of ways to do it securely. I'd avoid rolling my own, as this is definitely an area that you want to build upon the work of others, as there are a million little things you have to account for or else your installation is vulnerable to being circumvented.

      this needs to be fairly cross-platform. What is an example of "process accounting"? what mechanisms can I employ without patching any shells?
        Without patching existing shells and avoiding process accounting on your system, your only recourse is to write yourself your own shell. The security issues involved with this make this solution impractical, so I'm afraid I have no advice for you aside from that already given. Consider that if you write your own shell, you're going to have to find some way to selectively grant access to other shells on your system, so that shell scripts can run, but interactive sessions cannot be started (thus allowing the users to execute commands via the other shell, avoiding your logging). This is non-trivial. Your best solution is to take advantage of process accounting.

        Any mechanism like this is going to be inherently platform-specific. If this is a Unix system, contact your system administrator for information on configuring your system to enable process accounting, assuming it isn't already enabled. This is something that occurs at a relatively low level in Unix (but is supported essentially the same across a variety of Unix types), which is where it needs to be, since shells provide control to the system at such a high level, they can be easily tricked or circumvented, given that a lot of programs trust shells and have ways of allowing the user to drop to one.

Re: wrapping any given shell
by zigster (Hermit) on Feb 07, 2001 at 14:16 UTC
    How about using the unix script command. Quote from the manual:
    script makes a record of everything printed on your screen. The record is written to filename. If no file name is given, the record is saved in the file typescript. The script command forks and creates a sub-shell, according to the value of $SHELL, and records the text from this ses- sion. The script ends when the forked shell exits or when CTRL-D is typed.
    --

    Zigster
Re: wrapping any given shell
by enoch (Chaplain) on Feb 07, 2001 at 10:15 UTC
    If I were in your situation, I would just run a nightly job that appended their history file to a central file ('/tmp/user_logs/user.history').
    @users = qw(fred wilma barney); #watch these users foreach $user (@users) { open(LOG,">>$user.history"); open(HSTRY,"/$user/.bash_history"); while(<HSTRY>) { print LOG $_; } }
    If that wouldn't work for you and you really don't want to write a simple shell (which would amount to a bunch or fork's and exec's, really); you could try to write a daemon that would run and when a specified user logged in, it would dup() his STDIN to a file. (Note: the following code does not do this, but is an example of dup() ).
    open(LOG, ">>/tmp/$user.logfile"); open(STDIN, ">&LOG");
    But, again, you would have to make that a daemon that would watch people logging in, grab their username, expect the username, and then permanently dup() their STDIN.

    Good Luck,
    Jeremy

      You could use something like Unix::ConfigFile to fetch a list of users on your system, pull out each home directory using Unix::ConfigFile::home(), then use File::Tail to read their history files in, real-time.

      From here, you could either write the information to write-only media, or log it to files that are read/writeable only as root.