Monitoring /etc/passwd file - linux

I need a script that will check any modification in the /etc/passwd file, if there's a modification I get alerted immediately via email telling me that a user that has been added or removed from the passwd file
Without using inotifywait command

You could use the inotifywait utility, something like this:
inotifywait -e modify /etc/passwd
inotifywait will exit when the selected file is written, so you can take whatever action you need.

you could check for modifications with md5sum or sha256...
make your base checksum, hardcode it in a scrip
if [[ "$(sha256 /etc/passwd)" != "the hash of ori file" ]]; then
mail yourself
fi
you could also have a copy of /etc/passwd somewhere and run a diff that you send by mail as to have the content of the changes
if [[ "$(diff /etc/passwd /root/passwdbackup)" != "" ]]; then
mail yourself
fi

Related

Testing file content

I need help for bash scripting
I have a folder with log files(number may vary)
I have to test those files for content and if one or more of those files has content, I want to send the content by mail (I use mailx) being formatted like so:
The content of "filename" is:
------content---------
The content of "filename2" is:
------content---------
There was no content in "filename3".
Any practical way using bash to do this?
Thanks for your help.
shopt -s nullglob
for i in *; do
if [[ -s "$i" ]]; then
echo "file $i exists and is not empty"
fi
done
See: man bash

Script to check the change of crontab using diff

I need a script which needs to look in a way that take copy of the current crontab in a file then every day a cron tab copy needs to be taken and it needs to compare using "diff" command if it is not matching it needs to send alert mail.Can any one please help me on this?
Currently I'm using the below script But issue with this script is it sends alerts even if the Changes made in the crontab are correct.But I want to compare the contents using the diff command.So this script not suits for my requirement
#!/bin/sh
export smtp=smtprelay.intra.coriant.com:25
CROND=/home/ssx00001
ALERT=redmine#coriant.com
checkf=last.crontab.check
if [ -f $checkf ]
then
find $CROND -type f -newer $checkf | while read tabfile
do
echo "Crontab file for Redmine has changed" | mail -s "Crontab changed" $ALERT
done
fi
touch $CHECKF
#!/bin/sh
export smtp=smtprelay.intra.coriant.com:25
ALERT=redmine#coriant.com
crontab -l > /home/ssx00001/y.txt
cat y.txt
diff /home/ssx00001/x.txt /home/ssx00001/y.txt > /home/ssx00001/z.txt
ab=`cat z.txt | wc -l`
echo $ab
if [[ $ab != 0 ]]; then
echo "Crontab for Redmine has changed" | mail -s "Crontab modified" $ALERT
fi
(/home/ssx00001 is the path in which files stored ?)
Also create a file in /home/ssx00001 as x.txt which contains data of current cronjobs
The problem you have is that the diff command requires two files to compare. You cannot check for changes in a file without saving an old version of the file to check against. The crontab command does not do this.
Your best bet is to write a wrapper around the crontab command which saves a copy of the original crontab file, runs crontab to edit and install the new file, and then runs diff with the file you saved.

For every file modification copy it into another file bash

I want to run service to listen on file modifying and for every add to file delete it from file and append to another file
I tried this code but it is not working it like going in infinite loop
inotifywait -m -e modify "$1" |
while read folder eventlist eventfile
do
cat "$1">>$DESTINATION_FILE
>$1
done
Each time you truncate the file, that registers as a modification, which triggers another truncation, etc. Try testing if the file contains anything in the body of the loop.
inotifywait -m -e modify "$1" |
while read folder eventlist eventfile
do
# Only copy-and-clear if the file is not empty
if [ -s "$1" ]; then
cat "$1" >> "$DESTINATION_FILE"
# What if the file is modified here?
>$1
fi
done
See my comment between cat and the truncation. You would never put those modifications in $DESTINATION_FILE, because you would erase them before the next iteration of the loop. This isn't really avoidable, unless your operating system allows you to obtain a lock on $1 prior to the cat, then release the lock after the truncation, so that only one process can write to the file at a time.
As pointed out by chepner, the reverting of the changes will also be treated as file modify.
A way out is:
remove -m parameter
Manually implement a while loop in bash
e.g.
cp "$1" "$1.bak"
while true; do inotifywait -e modify "$1" | {
read folder eventlist eventfile;
cat "$1" >> "$DESTINATION_FILE";
# OR
# diff "$1" "$1.bak" >> "$DESTINATION_FILE";
cp "$1.bak" "$1";
}
done
Note: I haven't tested above code myself.
Note2: There may be atomicity issues. There are times when the file modifications are not being monitored. Hence, when this cat > operation or cp operations are in progress, someone may attempt to write to "$1" file, which will be missed.

root running cron task can't read .txt file generated by www-data user

I have a simple php page that writes a file to my server.
// open new file
$filename = "$name.txt";
$fh = fopen($filename, "w");
fwrite($fh, "$name".";"."$abbreviation".";"."$uid".";");
fclose($fh);
I then have a cron job that I know runs as root as test that and need that.
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root" 1>&2
exit 1
fi
The cronjob is a bash script that can detect the file exists, but it can't seem to read the contents of the file.
#!/bin/bash
######################################################
#### Loop through the files and generate coincode ####
######################################################
for file in /home/test/customcoincode/queue/*
do
echo $file
chmod 777 $file
echo "read file"
while read -r coinfile; do
echo $coinfile
echo "Assign variables from file"
#############################################
#### Set the variables to from the file #####
#############################################
coinName=$(echo $coinfile | cut -f1 -d\;)
coinNameAbreviation=$(echo $coinfile | cut -f2 -d\;)
UId=$(echo $coinfile | cut -f3 -d\;)
done < $file
echo "`date +%H:%M:%S` - $coinName : Your Kryptocoin is being compiled!"
echo $file
echo "copy $coinName file to generated directory"
cp -b $file /home/test/customcoincode/generatedCoins/$coinName.txt
echo "`date +%H:%M:%S` : Delete queue file"
# rm -f $file
done
echo $file recognises the file exists
echo $coinfile is blank
Yet when I nano ./coinfile.txt in terminal I can see clearly there is text in there
I run ls -l and I see that the file has the permissions
-rw-r--r-- 1 www-data www-data
I was under the impression that this would still mean the file can be read by other users?
Do I need to be able to execute the file if i am opening it and reading the contents?
Any advice would be greatly appreciated. I can expand and show my code if you want, but it was working before when I called a bash script to write the file... and that time it would save the file under root user with rwx for most and then could be read. But this then caused other issues in the php page, so is not an option.
You have:
while read -r coinfile; do
...
I see no indication that you're reading from $file. The command
read -r coinfile
will simply read from standard input (the -r merely affects the treatment of backslashes). In a cron job, if I recall correctly, standard input is empty or unavailable, which would explain why $coinfile is empty.
If you actually do read from $file -- for example, if your real code looks something like:
while read -r coinfile; do
...
done <$file
then you need to show us your entire script, or at least a self-contained version of it that exhibits the problem. Actually, you need to show us your entire script whether that's the problem or not.
http://sscce.org/

Bash: Create a file if it does not exist, otherwise check to see if it is writeable

I have a bash program that will write to an output file. This file may or may not exist, but the script must check permissions and fail early. I can't find an elegant way to make this happen. Here's what I have tried.
set +e
touch $file
set -e
if [ $? -ne 0 ]; then exit;fi
I keep set -e on for this script so it fails if there is ever an error on any line. Is there an easier way to do the above script?
Why complicate things?
file=exists_and_writeable
if [ ! -e "$file" ] ; then
touch "$file"
fi
if [ ! -w "$file" ] ; then
echo cannot write to $file
exit 1
fi
Or, more concisely,
( [ -e "$file" ] || touch "$file" ) && [ ! -w "$file" ] && echo cannot write to $file && exit 1
Rather than check $? on a different line, check the return value immediately like this:
touch file || exit
As long as your umask doesn't restrict the write bit from being set, you can just rely on the return value of touch
You can use -w to check if a file is writable (search for it in the bash man page).
if [[ ! -w $file ]]; then exit; fi
Why must the script fail early? By separating the writable test and the file open() you introduce a race condition. Instead, why not try to open (truncate/append) the file for writing, and deal with the error if it occurs? Something like:
$ echo foo > output.txt
$ if [ $? -ne 0 ]; then die("Couldn't echo foo")
As others mention, the "noclobber" option might be useful if you want to avoid overwriting existing files.
Open the file for writing. In the shell, this is done with an output redirection. You can redirect the shell's standard output by putting the redirection on the exec built-in with no argument.
set -e
exec >shell.out # exit if shell.out can't be opened
echo "This will appear in shell.out"
Make sure you haven't set the noclobber option (which is useful interactively but often unusable in scripts). Use > if you want to truncate the file if it exists, and >> if you want to append instead.
If you only want to test permissions, you can run : >foo.out to create the file (or truncate it if it exists).
If you only want some commands to write to the file, open it on some other descriptor, then redirect as needed.
set -e
exec 3>foo.out
echo "This will appear on the standard output"
echo >&3 "This will appear in foo.out"
echo "This will appear both on standard output and in foo.out" | tee /dev/fd/3
(/dev/fd is not supported everywhere; it's available at least on Linux, *BSD, Solaris and Cygwin.)

Resources