34

What I want to achieve is be able to record my terminal sessions to file automatically whenever I use Yakuake/Konsole.

It's easy to achieve if at the start of my session I do:

script -f /home/$USER/bin/shell_logs/$(date +"%d-%b-%y_%H-%M-%S")_shell.log

But I want to run the above automatically whenever I start Yakuake or open a new tab.

Using .bashrc does not work because it creates endless loop as 'script' opens a new session, which in turn reads .bashrc and starts another 'script' and so on.

So presumably I need to script Yakuake/Konsole somehow to run 'script' once as a new tab gets opened. The question is how?

2
  • try the problematic solution with the loop problem, but prepend the exec at the start of the line. it should start the script -f in the same shell PID.
    – Hanan
    Nov 29, 2011 at 22:28
  • Also interesting etended version of this quesion is how-to force as root the non-wheel users to script all their sessions as well ... May 28, 2014 at 20:33

3 Answers 3

37

If someone wants to record their terminal sessions automatically--including SSH sessions(!)--using the script utility, here is how.

Add the following line at the end of .bashrc in your home directory, or otherwise /etc/bash.bashrc if you only want to record all users' sessions. We test for shell's parent process not being script and then run script.

For Linux:

test "$(ps -ocommand= -p $PPID | awk '{print $1}')" == 'script' || (script -f $HOME/$(date +"%d-%b-%y_%H-%M-%S")_shell.log)

For BSD and macOS, change script -f to script -F:

test "$(ps -ocommand= -p $PPID | awk '{print $1}')" == 'script' || (script -F $HOME/$(date +"%d-%b-%y_%H-%M-%S")_shell.log)

That's all!

Now when you open a new terminal you'll see:

Script started, file is /home/username/file_name.log

script will write your sessions to a file in your home directory naming them something like 30-Nov-11_00-11-12_shell.log as a result.

More customization:

  • You can append your sessions to one large file rather than creating a new one for every session with script -a /path/to/single_log_file
  • You can adjust where the files are written to by changing the path after script -f (Linux) or script -F (BSD and macOS)

This answer assumes that you have script installed, of course. On Debian-based distributions, script is part of the bsdutils package.

4
  • You can edit your question and its title yourself. Just click on the edit button that appears right below it.
    – Mat
    Nov 30, 2011 at 6:51
  • 8
    You might want to consider adding a ${RANDOM} and/or $$ to the file name since starting two shells within a second of each other will cause a file-name collision. Personally, i often use script.$(date -u +%Y%m%dt%H%M%S).${HOSTNAME:-$(hostname)}.$$.${RANDOM}.log to ensure the files are automatically sorted by date/time and they are consistent accross TZ, i know the host that initiated it, i know the owning process, and there are no name collisions. I rarely use ${USER} because it's typically something for only me.
    – nicerobot
    Dec 2, 2011 at 16:33
  • "make sure you've actually created /var/log/script and made it writable by others" you wrote. I was wondering if it is advisable from security perspective to use "sudo chmod 777 /var/log/script" in this case.
    – Ertugrul
    Jul 1, 2017 at 16:07
  • On Linux at least this has the weird effect that when I try to exit from the shell I am left in the shell which called script, whereas if I append "exit" to after the test/script I can no longer get a shell as it seemingly exits immediately!
    – Michael
    May 5, 2020 at 0:38
11

Although this question was asked by an individual wanting to record his own sessions, an alternative use case might be a system administrator who wants to keep track of what various users are doing.

I fear running script inside the system-wide bashrc might not be suitable in the case when users of the machine are reluctant to have recordings made of their sessions.

Users who wish to remain incognito could bypass the logging by asking sshd to open a different shell (e.g. zsh) or run bash --rcfile ___ to prevent /etc/bash.bashrc from being loaded.

An alternative approach

This guide from 2008 (archived) uses a different method to force script to be run when a user logs in with ssh, which requires users to log in with a public/private key.

This is done by adding a script to the user's .ssh/authorized_keys file, in front of the key:

command="/usr/local/sbin/log-session" ssh-dss AAAAB3NzaC1kc3MAAAEBAMKr1HxJz.....

The log-session (archived) script then decides whether or not to run /usr/bin/script to log this user's session.

exec script -a -f -q -c "$SSH_ORIGINAL_COMMAND" $LOGFILE

To prevent the user from removing the added command, the administrator will need to assume ownership of the user's authorized_keys file.

chown root:root ~user/.ssh/authorized_keys

Unfortunately, this means the user won't be able to add any additional keys him/herself, or more importantly revoke the existing key if it is compromised, which is far from ideal.

Caveats

It is common for sshd's default configuration to allow users to perform SFTP over their ssh login. This offers a way for users to edit files without the changes being logged. If the administrator does not want users to be able to do that, then he should either enable some logging for SFTP, or disable the service. Although even then, users could still make unseen changes to files by running something like this in their terminal:

curl "http://users.own.server/server/new_data" > existing_file

It might be possible to monitor changes like that by using a copy-on-write filesystem that records all file history.

But a similar trick would allow a user to execute commands without them being logged:

curl "http://users.own.server/server/secret_commands_824" | sh

I don't know of any easy solutions to that. Possibilities might be:

  • Logging all network data (and untangling it later).
  • Logging all system calls.

This sort of thing might be possible with auditd.

But anyway...

It is unlikely that logging user sessions provides any real security for administrators. By default a user can only manipulate their own files, and cannot harm the system. If a malicious user did manage to escalate privileges, then he could disable logging and delete the logs (unless the administrator has configured logs to be stored on a separate machine, in an append-only fashion).

Administrators who do automatically log user sessions should probably inform the users that this is being done. In some jurisdictions, this form of data collection might violate data or privacy laws. And at the very least, it would be respectful to users to make them aware.

It is more likely that an administrator would be interested in logging the sessions of sudo users. That could perhaps be tackled in a different answer, or indeed a different question.

4

Instead of:

test "$(ps -ocommand= -p $PPID | awk '{print $1}')" == 'script' ||

I would use:

grep -qx "$PPID" <(pgrep -x "script") ||

The double-quotes aren't necessary in this case, but I tend to use them anyway as a standard practice. I definitely recommend using the "x" switch to both the grep and the pgrep, to avoid a rare-but-problematic match with substrings.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .