Monitor linux users logins and logouts script - linux

My problem is I need to monitor all the users that have logged on or logged out in real time. I know there is auth.log file, but I don't have permissions to it. Is there any way of displaying only the usernames and login/logout time?

To see which users are currently logged in, there are traditionally the commands who and w on Unix systems. Calling these is not restricted. Due to privacy reasons normal users should not be allowed to see when which users logged on or off.
That is the reason why what you want to do cannot be achieved properly with what is available to you. You will have to use workarounds each of which will have caveats.
The answer of Michael tries to achieve your goal by logging the list of current users (he's using ps but I would prefer who or w for this task). If this is done regularly (each minute or each hour or so) then later you can scan your log file to find out when who appeared and disappeared. I'd use it like this:
#!/bin/bash
log() {
line=$(who | cut -d' ' -f1 | sort -u)
echo "$(date): " $line # _NO_ quotes around $line!
}
while sleep 3600
do
log >> user.log
done & # do this in the background
Each hour this will log who is online into the file user.log.

You can use trace logged users with focus on running processes. Following scenario do it:
#!/bin/sh
mv current.log previous.log #Use two log file for compare users
ps aux | awk " {print $ 1}" |sort | uniq > current.log #Here unique users list
diff current.log previous.log | grep ">\|<" #comparring users lists
In result you can view next:
< avahi #logout user
> 123 #login user
> sfdfs #login user

Also, maybe the last command is what you can use.

Related

Pass variables out of an interactive session from bash script

Hello People of the world,
I am trying to write a script that will allow user to failover apps between sites in bash.
Our applications are controlled by Pacemaker and I thought I would be able to write a function that would take in the necessary variables and act. Stop on one site, start on another. Once I have ssh'd to the remote machine, I am unable to get the value of the grep/awk command back for the status of the application in PCS.
I am encountering a few issues, and have tried answers from stackoverflow and other sites.
I send the ssh command to /dev/null 2>&1 as banners pop up on screen that unix admin have on the local user and -q does not deal with it - Does this stop anything being returned?
when using awk '{print \\\\\\$4}' in the code, I get a "backslash not last character on line" error
To get round this, I tried result=$(sudo pcs status | grep nds_$resource), however this resulted in a password error on sudo
I have tried >/dev/tty and >$(tty)
I tried to not suppress the ssh (remove /dev/null 2>&1) and put the output in variable at function call, removing the awk from the sudo pcs status entry.
result=$(pcs_call "$site1" "1" "2" "disable" "pmr")
echo $result | grep systemd
This was OK, but when I added | awk '{print \\\$4}' I then got the fourth word in the banner.
Any help would be appreciated as I have been going at this for a few days now.
I have been looking at this answer from Bruno, but unsure how to implement as I have multiple sudo commands.
Below is my strip down of the function code for testing on one machine;
site1=lon
site2=ire
function pcs_call()
{
site=$1
serverA=$2
serverB=$3
activity=$4
resource=$5
ssh -tt ${site}servername0${serverA} <<SSH > /dev/null 2>&1
sudo pcs resource ${activity} proc_${resource}
sleep 10
sudo pcs status | grep proc_$resource | awk '{print \\\$4}' | tee $output
exit
SSH
echo $output
}
echo ====================================================================================
echo Shutting Down PMR in $site1
pcs_call "$site1" "1" "2" "disable" "pmr"
I'd say start by pasting the whole thing into ShellCheck.net and fixing errors until there are no suggestions, but there are some serious issues here shellcheck is not going to be able to handle alone.
> /dev/null says "throw away into the bitbucket any data that is returned. 2>&1 says "Send any useful error reporting on stderr wherever stdout is going". Your initial statement, intended to retrieve information from a remote system, is immediately discarding it. Unless you just want something to occur on the remote system that you don't want to know more about locally, you're wasting your time with anything after that, because you've dumped whatever it had to say.
You only need one backslash in that awk statement to quote the dollar sign on $4.
Unless you have passwordless sudo on the remote system, this is not going to work out for you. I think we need more info on that before we discuss it any deeper.
As long as the ssh call is throwing everything to /dev/null, nothing inside the block of code being passed is going to give you any results on the calling system.
In your code you are using $output, but it looks as if you intend for tee to be setting it? That's not how that works. tee's argument is a filename into which it expects to write a copy of the data, which it also streams to stdout (tee as in a "T"-joint, in plumbing) but it does NOT assign variables.
(As an aside, you aren't even using serverB yet, but you can add that back in when you get past the current issues.)
At the end you echo $output, which is probably empty, so it's basically just echo which won't send anything but a newline, which would just be sent back to the origin server and dumped in /dev/null, so it's all kind of pointless....
Let's clean up
sudo pcs status | grep proc_$resource | awk '{print \\\$4}' | tee $output
and try it a little differently, yes?
First, I'm going to assume you have passwordless sudo, otherwise there's a whole other conversation to work that out.
Second, it's generally an antipattern to use both grep AND awk in a pipeline, as they are both basically regex engines at heart. Choose one. If you can make grep do what you want, it's pretty efficient. If not, awk is super flexible. Please read the documentation pages on the tools you are using when something isn't working. A quick search for "bash man grep" or "awk manual" will quickly give you great resources, and you're going to want them if you're trying to do things this complex.
So, let's look at a rework, making some assumptions...
function pcs_call() {
local site="$1" serverA="$2" activity="$3" resource="$4" # make local and quotes habits you only break on purpose
ssh -qt ${site}servername0${serverA} "
sudo pcs resource ${activity} proc_${resource}; sleep 10; sudo pcs status;
" 2>&1 | awk -v resource="$resource" '$0~"proc_"resource { print $4 }'
}
pcs_call "$site1" 1 disable pmr # should print the desired field
If you want to cath the data in a variable to use later -
var1="$( pcs_call "$site1" 1 disable pmr )"
addendum
Addressing your question - use $(seq 1 10) or just {1..10}.
ssh -qt chis03 '
for i in {1..10}; do sudo pcs resource disable ipa $i; done;
sleep 10; sudo pcs status;
' 2>&1 | awk -v resource=ipa '$0~"proc_"resource { print $2" "$4 }'
It's reporting the awk first, because order of elements in a pipeline is "undefined", but the stdout of the ssh is plugged into the stdin of the awk (and since it was duped to stdout, so is the stderr), so they are running asynchronously/simultaneously.
Yes, since these are using literals, single quotes is simpler and effectively "better". If abstracting with vars, it doesn't change much, but switch back to double quotes.
# assuming my vars (svr, verb, target) preset in the context
ssh -qt $svr "
for i in {1..10}; do sudo pcs resource $verb $target \$i; done;
sleep 10; sudo pcs status;
" 2>&1 | awk -v resource="$target" '$0~"proc_"resource { print $2" "$4 }'
Does that help?

Linux : Send message when a user logs in

I must create a Shell that when a user logs in, it will print on the terminal from which the connection was made how many users are logged in an their number of processes.
The second part ( the one with processes ) was easy, thanks you the following command
ps hax -o user | sort | uniq -c
But I can't go any further. I don't know how to automatically launch this script for every user, and even more, how to write on their terminal. ( I fount commands like msg, write but all require me to insert the username)
Your command ps hax -o user | sort | uniq -c does not show count of processes of logged in users but of every user (including system accounts) not necessarily currently logged in.
List of only logged in users can be get with who command.
To get count of processed per logged in user one can try:
for u in `who -u | cut -f1 -d' ' | sort -u`; do echo -n "$u "; ps hx -u $u | wc -l; done;
Message displayed on users terminal only at login time is set in /etc/motd test file. This is static file. What you need is dynamically generated motd file. This can be achieved with update-motd.
On Ubuntu/Debian update-motd configuration scripts can be found in /etc/update-motd.d/
I'm not sure if similar feature is available on RedHat like systems but you can search for update-motd or dynamic motd.
If you want the message to appear only each time the user opens the terminal, you can edit /etc/bash.bashrc and include the .sh script from there. This file basically contains commands that get executed every time a terminal is opened.

run the disk space checking script in linux without login

I wrote a script for checking the disk space in the linux machine using shell script when i am login.
Now if i am not login in that machine but i need an alert if the disk space is more than the threshold (ex:80) means how can i check?
1.Using ssh (remote command execution)
2.Run as a background script.
Which one is more efficient?
or is there any other ideas to do this?
I do not want to do any kind of login directly/indirectly. ie. I even don't want to use ssh keygen to store keys. It should work like the webpages, with any new systems also but without any kind of security tuning
Pls let me know.
The cron program is a good place to start. It is available on any Linux system, and can be setup to run programs at regular intervals. If the program produces error messages, those are normally emailed to the account which create the cron job.
Script for checking the disk usage and cpu usage
ALERT=60
df command is used to check the list of disks available and their attributes.Here we get the Filesystem information and take name of the file system and usage of the file
system through awk command.Next for getting the value we cut the % symbol and get the interger only.Then we check the condition for Alert Message.
df -H | grep -vE '^Filesystem' | awk '{ print $5 " " $1 }' | while read output; do
usep=$(echo $output | awk '{ print $1}'| cut -d '%' -f1 )
partition=$(echo $output | awk '{ print $2 }' )
if [ $usep -ge $ALERT ]; then
echo "Alert: Almost out of disk space $usep $partition $HOSTNAME"
fi
done
This is the script i have written for checking the disk space.
Then i gave crontab -e command in the terminal add the script to the file.Now the new cron job is assigned.i set the cronjob to be executed for every 1 hour to monitor the disk space check.
So,Now i can't able to get the message notification.If i am not logged in in that machine,How to get the information about the disk space check?
Is there any thing needs to improve in the script?

How to grep for the next instance of a variable in a logfile?

So I am trying to parse FTP logs and see if a certain user is logging in securely. So far I have this to pull the next couple of lines after the user logs in
cat proftpd.log.2 | grep -B 3 "USER $sillyvariable"
and this is a sample output it creates
::ffff:127.0.0.0 UNKNOWN ftp [04/Jan/2013:11:03:06 -0800] "AUTH TLS" 234 -
::ffff:127.0.0.0 UNKNOWN ftp [04/Jan/2013:11:03:06 -0800] "USER $sillyvariable" 331 -
Now this is a perfect example of what I want, it displays the AUTH TLS Message and the IPs match. However this is not always the case as many users are constantly logging in and out and most of the time the output is jumbled.
Is there a way I can grep for the USER $sillyvariable and find his/her matched IP containing the "AUTH TLS" in the preceding line so I can know they logged in securely? I guess you can say I want to grep the user and then grep backwards to see if the connection they originated from (matching IPs) was secure. I'm kind of stuck on this and could really use some help.
Thanks!
$ grep -B3 'USER $sillyvariable' proftpd.log.2 |
tac | awk 'NR==1 {IP=$1} $1==IP {print}' | tac
::ffff:127.0.0.0 UNKNOWN ftp [04/Jan/2013:11:03:06 -0800] "AUTH TLS" 234 -
::ffff:127.0.0.0 UNKNOWN ftp [04/Jan/2013:11:03:06 -0800] "USER $sillyvariable" 331 -
This uses tac to reverse the lines in the grep result. It then looks for all lines where the IP addresses match the one in the USER line. Finally it runs tac again to put the lines back in the original order.
I realize I am very late to this party, but the comment I made about the AUTH statement possibly being more than 3 lines earlier left me wondering.
I took a slightly different approach, in which I make minimal assumptions (based on limited knowledge of the contents of your log file):
There is one user per IP address (may not be true if they are behind a firewall)
For every AUTH entry there should be exactly one "good" USER entry from the same IP address
A sorted list of IP addresses which have entries in the log file will show more "USER" than "AUTH" requests for any IP address from which a "bad" request was made
If those assumptions are reasonable / true, then a simple bash script does quite a nice job of giving you exactly what you want (which is a list of the users that didn't log in properly - which is not exactly what you were asking for):
#!/bin/bash
# first, find all the "correct" IP addresses that did the login "right", and sort by IP address:
grep -F "AUTH TLS" $1 | awk '{print $1}' | sort > goodLogins
# now find all the lines in the log file with USER and sort by IP address
grep USER $1 | awk '{print $1}' | sort > userLogins
# now see if there were user logins that didn't correspond to a "good" login:
echo The following lines in the log file did not have a corresponding AUTH statement:
echo
sdiff goodLogins userLogins | grep "[<>]" | awk '{print $2 ".*USER"}' > badUsers
grep -f badUsers $1
echo -----
Note that this leaves you with three temporary files (goodLogins, userLogins, badUsers) which you might want to remove. I assume you know how to create a text file with the above code, set it to be executable ( chmod u+x scrubLog ), and run it with the name of the log file as parameter ( ./scrubLog proftpd.log.2 ).
Enjoy!
PS - I am not sure what you mean by "logging in correctly", but there are other ways to enforce good behaviors. For example, you could block port 21 so only sftp (port 22) requests come through, you could block anonymous ftp, ... But that's not what you were asking about.

Most reliable way to identify the current user through a sudo

I have an application that may or may not be run while users are sudo'ed to a shared user account. I would like to reliably identify who the real user is for a sort of "honor-system" ACL. I think there's some way by tracing parent/group/session process ids the way that the pstree command does, but I'm not sure how to do that best or if there are better alternatives.
I tried getlogin() originally. That works if ./myapp is used, but it fails with 'cat input | ./myapp` (because the "controlling terminal" is a pipe owned by the shared account).
I'd rather not trust environment variables, as I don't want my "honor system" to be completely thwarted by a simply unset, when the information is still available elsewhere.
I'd also like to avoid forcing a lookup in the password database, as that is a remote RPC (NIS or LDAP) and I'm pretty sure wtmp already contains the information I need.
For a shell script, you might use this to get the sudo'ing user:
WHO=$(who am i | sed -e 's/ .*//'`)
and extract the id from the login using:
ID_WHO=$(id -u $WHO)
I'll ferret out the C library equivalent later.
sudo sets the environment variables SUDO_USER, SUDO_UID, and SUDO_GID.
You can test this with:
$ sudo env
[sudo] password for shteef:
TERM=xterm
# [...snip...]
SHELL=/bin/bash
LOGNAME=root
USER=root
USERNAME=root
SUDO_COMMAND=/usr/bin/env
SUDO_USER=shteef
SUDO_UID=1000
SUDO_GID=1000
But if your users have shell access on the shared account, then I suppose you cannot blindly trust this either.
How about:
#!/usr/bin/ksh
username=`id | cut -d"=" -f2 | cut -d" " -f1`
if [ $username == "0(root)" ]
then
print "Yes, the user is root"
else
print "Sorry! the user $username, is not a root"
fi

Resources