Thursday, April 12, 2012

How to log commands executed by all the users in Linux?

By adding the following entry in /etc/bashrc, we can log the commands executed by all the users on a Linux machine. 
This would be certainly helpful for tracking commands on Critical servers.

PROMPT_COMMAND='history -a >(logger -t "$USER[$PWD] $SSH_CONNECTION")'

After you add the above entry at the end of /etc/bashrc file, execute the command 'source /etc/bashrc' or logout and login back to your session. Now the commands executed by all the users will be logged in /var/log/messages.
Note: If you wish to log the commands on to a different file, please check the solution given in the comments section.

Sample test result:

Apr 18 13:35:21 Linux-Mach root[/root] 192.168.4.5 51650 172.16.0.252 22: uptime
Apr 18 13:35:24 Linux-Mach root[/opt] 192.168.4.5 51650 172.16.0.252 22: cd /opt
Apr 18 13:35:26 Linux-Mach root[/opt] 192.168.4.5 51650 172.16.0.252 22: ls -lR
Apr 18 13:35:35 Linux-Mach root[/opt] 192.168.4.5 51650 172.16.0.252 22: iostat -x 2
Apr 18 13:35:39 Linux-Mach root[/root] 192.168.4.5 51650 172.16.0.252 22: cd /root
Apr 18 13:35:39 Linux-Mach root[/root] 192.168.4.5 51650 172.16.0.252 22: ls -l
Apr 18 13:35:51 Linux-Mach root[/home] 192.168.4.5 51650 172.16.0.252 22: cd /home
Apr 18 13:35:52 Linux-Mach root[/home] 192.168.4.5 51650 172.16.0.252 22: ls
Apr 18 13:35:56 Linux-Mach root[/home] 192.168.4.5 51650 172.16.0.252 22: httpd -t

Apr 18 13:51:24 Linux-Mach test1[/home/test1] 192.168.6.8 9106 172.16.0.252 22: ls -l
Apr 18 13:53:20 Linux-Mach test1[/var/lock/subsys] 192.168.6.8 9106 172.16.0.252 22: cd /var/lock/subsys
Apr 18 13:53:30 Linux-Mach test1[/var/lock/subsys] 192.168.6.8 9106 10.160.0.252 22: ls -ltr


Updated one:

# echo $PROMPT_COMMAND

RETRN_VAL=$?;logger -p local3.debug "$(whoami)  $remoteip  [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//") [$RETRN_VAL]"


On RHEL 8.x



[root@rhel8 ]# cat /etc/profile.d/prompt.sh 

remoteip=$(who am i | awk '{print $5}' | sed "s/[()]//g")

export PROMPT_COMMAND='RETRN_VAL=$?;logger -p local3.debug "$(whoami)  $remoteip  [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//") [$RETRN_VAL]"'

[root@rhel8 ]# 

29 comments:

  1. This was an excellent one, is their any option to store the command in different location instead of /var/log/message

    ReplyDelete
  2. Hi Siva, Good question. It should be possible by adjusting the Syslog facility. I will come out with a solution soon.

    ReplyDelete
  3. Hi Siva, Here's the solution for you to log the commands on to different file.

    Lets say you want to capture the command execution in a different file called "/var/log/usercommands".

    Open the /etc/syslog.conf file and insert the syslog facility entry (local[0-6].info) as shown below:

    *.info;mail.none;authpriv.none;cron.none /var/log/messages
    local2.info /var/log/usercommands

    (Please note that you can use the Syslog facility "local0-6" for any purpose)

    After this, restart the 'syslog' service.

    Update the entry in /etc/bashrc as follows:
    PROMPT_COMMAND='history -a >(logger -p local2.info -t "$USER[$PWD] $SSH_CONNECTION")'

    Run 'source /etc/bashrc'

    Now all the commands will be captured in /var/log/usercommands.

    Note: Using '-p' with logger command, we can redirect the logs to a different Facility with different priority defined in /etc/syslog.conf file.

    More details on Syslog facilities and priorities: http://content.hccfl.edu/pollock/aunix2/logging.htm

    ReplyDelete
  4. Thankyou for providing the solution

    ReplyDelete
  5. By making the variable "readonly" the end user cannot change it and conceal their actions.

    readonly PROMPT_COMMAND='history -a >(logger -t "$USER[$PWD] $SSH_CONNECTION")'
    or
    readonly PROMPT_COMMAND='history -a >(logger -p local2.info -t "$USER[$PWD] $SSH_CONNECTION")'

    ReplyDelete
  6. Wow...that was an Excellent tip Jason !! Thankyou so much !!

    ReplyDelete
  7. Guys, I'm getting the following error while running "source /etc/bashrc" command. Please help me out the resolution for this.

    /root# source /etc/bashrc
    -sh: PROMPT_COMMAND: line 5: syntax error near unexpected token `('
    -sh: PROMPT_COMMAND: line 5: `history -a >(logger -t "$USER[$PWD] $SSH_CONNECTION")'
    (**root**on usclswups011)
    /root#

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. @Basha, This is a Syntax error in /etc/bashrc file. It appears you are using a Back tick (`) instead of single-quote (') infront of "history -a". Please correct that and try.

    ReplyDelete
  10. Hi Ashok,

    Is there a way to transmit the user issue command to another server for instance a centralized logging server?

    ReplyDelete
    Replies
    1. Yes, there is.

      You just have to selectively ship a certain type of logs to a remote server. For ex, in rsyslog to ship all logs over UDP, you do something like:

      *.* @syslog.server.com

      You just need to replace *.* with more specific priority.

      Delete
  11. Yes, you can push the logs to Centralized Log server.

    -Ashok

    ReplyDelete
  12. This comment has been removed by the author.

    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. But this is not working for normal users

    ReplyDelete
  15. Hi Ashok, great tutorial! just one thing, this is not logging any user commands, it's logging just root commands. Is it possible to log in ALL users' commands? Thanks!!

    ReplyDelete
  16. In your bashrc if you put in a variable
    WHOIAM=l`who mom likes | awk '{print $1}'
    then put the variable in your
    readonly PROMPT_COMMAND='history -a >(logger -p local2.info -t "$WHOIAM:$USER[$PWD] $SSH_CONNECTION")'

    This way you will also log on one line if someone SU's to someone else. So if someone SU's to root you will see the commands as root and also be able to tell the origination user



    ReplyDelete
  17. whoops.. type
    WHOIAM=l`who mom likes | awk '{print $1}'
    should read
    WHOIAM=`who mom likes | awk '{print $1}'

    ReplyDelete
  18. You could use snoopy: https://github.com/a2o/snoopy

    ReplyDelete
  19. Hi Ashok,
    I keep getting
    -bash: PROMPT_COMMAND: readonly variable

    Pls help

    ReplyDelete
    Replies
    1. do an "unset -f PROMPT_COMMAND". Then login via another session and run "source /etc/bashrc". It worked for me

      Delete
  20. Hi Ashok,

    Thanks for nice guide, It's working as excepted,

    My case, I am exec. command and different machine, Not same machine, When I login the particular server executing some command means it's recording nicely.

    In my case ::
    I am executing 'df -H' command from different not recording.

    ssh sysops@172.16.30.215 'df -H'

    Please guide me.

    ReplyDelete
  21. I see the logs duplicated in "messages" file and also "usercommands" file. Is it possible to save the logs only in "usercommands" file and not is messages?

    ReplyDelete
  22. Hi,

    It works for me but it seems this solution is not logging commands if the user is always trying to execute same commands repeatedly.
    Ex.
    If the user is executing “uptime” command repeatedly, it is only logging once.
    If the user is executing “uptime” and then another command such as “ls -lrt” and then uptime, it is logging everything as expected.

    How we can fix this?

    ReplyDelete
  23. Fantastic article. Thank you.
    I agree with "THE MIRROR", it would be better if the commands are not getting written to /var/log/messages as well

    ReplyDelete
  24. is there any way to log every user command making their own respective user log file.

    ReplyDelete