Shell Script ssh $SERVER >> EOF - linux

I have a handy script here that can return accounts that will expire in 7 Days or have expired. I wanted to allow this to run on multiple hosts with out putting the script on each individual host, I added the for loop and the ssh $SERVER >> EOF part but it will just run the commands off they system that is running the script.
I believe the error is with ssh $SERVER >> EOF but I am unsure as the syntax looks correct.
#!/bin/bash
for SERVER in `cat /lists/testlist`
do
echo $SERVER
ssh $SERVER >> EOF
sudo cat /etc/shadow | cut -d: -f1,8 | sed /:$/d > /tmp/expirelist.txt
totalaccounts=`sudo cat /tmp/expirelist.txt | wc -l`
for((i=1; i<=$totalaccounts; i++ ))
do
tuserval=`sudo head -n $i /tmp/expirelist.txt | tail -n 1`
username=`sudo echo $tuserval | cut -f1 -d:`
userexp=`sudo echo $tuserval | cut -f2 -d:`
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=`date +"%s"`
if [[ $userexpireinseconds -ge $todaystime ]] ;
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]];
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done

Here documents are started by << EOF (or, better, << 'EOF' to prevent the body of the here document being expanded by the (local) shell) and the end marker must be in column 1.
What you're doing is running ssh and appending standard output to a file EOF (>> is an output redirection; << is an input redirection). It is then (locally) running sudo, etc. It probably fails to execute the local file EOF (not executable, one hopes), and likely doesn't find any other command for that either.
I think what you're after is this (where I've now replaced the back-ticks in the script with $(...) notation, and marginally optimized the server list generation for use with Bash):
#!/bin/bash
for SERVER in $(</lists/testlist)
do
echo $SERVER
ssh $SERVER << 'EOF'
sudo cat /etc/shadow | cut -d: -f1,8 | sed '/:$/d' > /tmp/expirelist.txt
totalaccounts=$(sudo cat /tmp/expirelist.txt | wc -l)
for ((i=1; i<=$totalaccounts; i++))
do
tuserval=$(sudo head -n $i /tmp/expirelist.txt | tail -n 1)
username=$(sudo echo $tuserval | cut -f1 -d:)
userexp=$(sudo echo $tuserval | cut -f2 -d:)
userexpireinseconds=$(( $userexp * 86400 ))
todaystime=$(date +"%s")
if [[ $userexpireinseconds -ge $todaystime ]]
then
timeto7days=$(( $todaystime + 604800 ))
if [[ $userexpireinseconds -le $timeto7days ]]
then
echo $username "is going to expire in 7 Days"
fi
else
echo $username "account has expired"
fi
done
sudo rm /tmp/expirelist.txt
EOF
done
Very close, but the differences really matter! Note, in particular, that the end marker EOF is in column 1 and not indented at all.

Related

How to limit concurrent SSH or Dropbear Tunnel connections

I need to limit concurrent SSH/Dropbear Tunnel connections to 1 login per user.
I have a script that takes care of that.
But it doesn't work for me because when there are many users it becomes saturated and it takes a long time to kick the users.
Another problem with this script is that if the user logs out and logs back in it is detected as multilogin.
Maxlogins and MaxSessions does not work on Dropbear.
Below is the script I am using:
#!/bin/bash
# This script locates all users who have multiple active dropbear
# processes and kills processes in excess of one for each user.
if [ "$EUID" -ne 0 ]; then
printf "Please run as root.\n"
exit
fi
IFS=+
while true; do
PIDFILE=$(mktemp)
AUTHFILE=$(mktemp)
USERS=$(mktemp)
ps aux | grep dropbear | grep -v grep | awk 'BEGIN{} {print $2}' > $PIDFILE
journalctl -r | grep dropbear | grep auth > $AUTHFILE
while read LINE; do
USER=$(printf "%s" $LINE | sed "s/^.* '//" | sed "s/'.*$//" -)
PID=$(printf "%s" $LINE | sed "s/^.*\[//" | sed "s/].*$//" -)
if grep -Fxq $(printf "%s" $USER) $USERS; then
:
else
printf "%s\n" $USER >> $USERS
fi
USERFILE=$(printf "/tmp/%s" $USER)
if [ ! -f $USERFILE ]; then
touch $USERFILE
fi
if grep -Fxq $(printf "%s" $PID) $PIDFILE; then
printf "%s\n" $PID >> $USERFILE
else
:
fi
done < $AUTHFILE
while read USER; do
i=1
while read PID; do
if [ $i -gt 1 ]; then
printf "Kill PID %s of user %s\n" $PID $USER
kill -9 $(printf "%s" $PID)
curl -k "https://redesprivadasvirtuales.com/modules/servers/openvpn/vega.php?secret=DD8sPD&user=$USER"
else
:
fi
((i++))
done < $(printf "/tmp/%s" $USER)
rm $(printf "/tmp/%s" $USER)
done < $USERS
rm $PIDFILE
rm $AUTHFILE
rm $USERS
done
Suggestions:
journalctl -r is very expensive. Limit journalctl to time since last search.
Line with USER=$(...) and PID=$(...). Replace printf and sed commands, with single awk command.
Research pgrep and pkill commaonds.
Replace file $PIDFILE $AUTHFILE $USERS with array variables (research readarray command).
While loop over $AUTHFILE could be implemented as loop over bash array.
While loop over $USERS (including internal loop) could be implemented as loop over bash array.
curl command might be very expensive. You do not check the response from each curl request. Run curl in background and if possible in parallel for all users.
Kind SO members could assist more, if you put sample lines from $AUTHFILE in the questions as sample input line.

Accept Multiple User Inputs

I'm trying to create a script, where multiple user inputs are being accepted. When I call the script, and provide multiple inputs the script won't execute when multiple inputs are provided. What am I doing wrong here.
#! /bin/bash
server_list=()
echo "Enter server name: "
readarray -t servername
declare -p servername
sudo showsudolocal $servername | tr -d '$' | sed -e '/^$/d' | tee output.txt
sed -i 1,8d output.txt
mapfile -t myArray < output.txt
count=${#myArray[#]}
for (( i=1; i<$count; ))
#for i in `seq 1 $count`
do
str="${myArray[$i]}"
echo "str is $str"
IFS=',' read -r -a array <<< "$str"
i=$((i+2))
username="${array[0]}"
groupname="${array[1]}"
echo "Username is $username"
if [[ -z "${array[0]}" ]] || [[ "${array[0]}" == *'*'* ]]
then
echo "group"
sudo docentcmd $servername centclicmd adquery group $groupname
cat /etc/group | grep $groupname
else
echo "User"
sudo docentcmd $servername centclicmd adquery user $username
cat /etc/passwd | grep $username
fi
done

Looping script, redirect to file

So I have this BASH script and what i want to do is, reach out to the servers. Check the used % of a directory. If it is higher than my set threshold (90) then print that server name to another file on the server where the script has been run from.
What it is doing is printing the first server name twice in to the file so it looks like
server1
server2
Here is my script ... I don't see why it would be going around in a loop to that first server twice
#!/bin/bash
SERVERS="server1
server2"
for i in $SERVERS; do
ssh $SERVERS "
df -h | grep var | awk '{print \$4}' | sed 's/%//g' > /home/user/space.txt
RESULTS=\$(grep -E "1[5-9]" /home/user/space.txt)
THRESHOLD=90
if [[ \$RESULTS -lt \$THRESHOLD ]]; then
exit 1;
elif [[ \$RESULTS -gt \$THRESHOLD ]]; then
hostname;
fi
" >> /home/user/problem.txt
done
Try this,
#!/bin/bash
SERVERS="server1
server2"
for i in $SERVERS; do
ssh "$i" "
df -h | grep var | awk '{print \$4}' | sed 's/%//g' > /home/user/space.txt
RESULTS=\$(grep -E "1[5-9]" /home/user/space.txt)
THRESHOLD=90
if [[ \$RESULTS -lt \$THRESHOLD ]]; then
exit 1;
elif [[ \$RESULTS -gt \$THRESHOLD ]]; then
hostname;
fi
" >> /home/user/problem.txt
done

sed is not working for commenting a line in a file using bash script

I have created a bash script that is used to modify the ulimit of open files in the RHEL server.
so i have reading the lines in the file /etc/security/limits.conf and if the soft/hard limit of the open files are less than 10000 for '*' domain i am commenting the line and adding a new line with soft/hard limit as 10000.
The Script is working as designed but the sed command to comment a line in the script is not working.
Please find the full script below :-
#!/bin/sh
#This script would be called by '' to set ulimit values for open files in unix servers.
#
configfile=/etc/security/limits.conf
help(){
echo "usage: $0 <LimitValue>"
echo -e "where\t--LimitValue= No of files you want all the users to open"
exit 1
}
modifyulimit()
{
grep '*\s*hard\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
grep '*\s*soft\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
}
deleteEofTag(){
sed -i "/\b\(End of file\)\b/d" $configfile
}
addEofTag()
{
echo "#################End of file###################" >> $configfile
}
#-------------Execution of the script starts here ----------------------
if [ $# -ne 1 ];
then
help
else
modifyulimit $1
deleteEofTag
addEofTag
fi
The command sed -i -e 's/$line/#$line/g' $configfile when executed from the terminal is working absolutely fine and it is commenting the line but it is not working when i am executing it from the unix shell script.
interpolation does not work in single quote
use double quote and try
sed -i -e 's/$line/#$line/g'
sed -i -e "s/$line/#$line/g"
also you might try:
sed -i -e s/${line}/#${line}/g
as this will tell the script to take the value of the variable instead of variable as such.

Verify account creation from text file in bash script

I am trying to output which accounts have been successfully created from a text file and which haven't. I would also like to output the number of successfully created accounts. I currently the get the following error: grep: 3: No such file or directory. The script and text file and saved in the same folder. I have use the following commands in my script.
file=users.txt
verify =grep "verify" $file |cut -f2 -d:`
cat /etc/passwd | grep $verify
echo -e "\nYou have Currently"
cat /etc/passwd | grep $verify |wc -l;
echo "users added from your Text File"
Edit:
#!/bin/bash
ROOT_UID=0 #The root user has a UID of 0
if [ "$UID" -ne "$ROOT_UID" ]; then
echo "**** You must be the root user to run this script!****"
exit
fi
clear
echo
echo "######################################################"
echo "##### Batch script to automate creation of users #####"
echo -e "######################################################\n"
while true;
do
file=notvalid
while [ $file == "notvalid" ]
do
#echo "repeat $repeat"
#echo -e "\n"
echo -n "Please enter import filename:"
read filename
echo -e "\r"
exists=0
if [ -e $filename ]; then
file=valid
while IFS=":" read firstname lastname userid password group
do
egrep -i "^$userid:" /etc/passwd &>/dev/null
if [ $? -eq 0 ]; then
exists=$((exists+1))
#echo -e "${firstname} ${lastname} already exists on the system"
#grep ${userid} /etc/passwd
aname=$( getent passwd "$userid" | cut -d: -f3)
echo "Account Exists: $aname"
euserid=$( getent passwd "$userid" | cut -d: -f1)
echo "User ID: $userid"
homedir=$( getent passwd "$userid" | cut -d: -f6)
echo "Home Directory: $homedir"
usershell=$( getent passwd "$userid" | cut -d: -f7)
echo "User Shell: $usershell"
g=$( id -Gn "$userid")
echo "Groups: $g"
echo -e "\r"
else
egrep -i "^$group:" /etc/group &>/dev/null
if [ $? -eq 1 ]; then
/usr/sbin/addgroup ${group} &>/dev/null
fi
useradd -d /home/"${userid}" -m -s /bin/bash -c \
"${firstname}${lastname}" -g "${group}" "${userid}"
echo "Creating Account: ${firstname} ${lastname}"
nuserid=$( getent passwd "$userid" | cut -d: -f1)
echo "Creating User ID: ${nuserid}"
{ echo ${password}; echo ${password}; } | sudo passwd ${userid} > /dev/null 2>&1
echo "Creating Password: ${password}"
echo "Creating Home Directory: /home/${userid}"
echo "Creating User Shell: /bin/bash"
echo -e "Assigning Group: ${group}\n"
fi
done < $filename
else
echo -e "##### CANNOT FIND OR LOCATE FILE #####"
fi
verify=`grep "verify" /home/pi/$filename | cut -f3 -d:`
echo "$verify"
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
while true
do
echo -n "Create additional accounts [y/n]: "
read opt
if [[ $opt == "n" || $opt == "y" ]];then
break
else
echo "Invalid Input"
fi
done
if [ $opt = "n" ]; then
clear
break
else
clear
fi
done
You were almost there.
The main issue with your approach is that you try to search for multiple accounts at once with grep. The variable verify has multiple userids so you need to process it one by one.
file=users.txt
verify=`grep "verify" $file | cut -f2 -d:`
count=0
for id in $verify
do grep -wo ^$id /etc/passwd && count=$((count+1))
done
echo $count users added from your text file
echo these are not added:
for id in $verify
do grep -wq ^$id /etc/passwd || echo $id
done
The for loop will take each element in your verify variable into id and search with grep (-w matches only whole words, not fragments, ^ matches the beginning of line and -o outputs only the matching word not the whole line).
We count the number of matches in the count variable. Alternative approach to run the for loop twice and pipe the second one to wc -l as you did.
&& operator means it will increase count if the previous command found a match (the return code of grep was 0).
The next loop will not print matching ids (-q), and will echo id if grep did not found a match (the return code was not 0). This is achieved with the || operator.
One last note on iteration of a list: if the members can contain spaces (unlike userids), you should use ${verify[#]} (this is a bash-ism) instead of $verify .
And forget this: cat /etc/passwd | grep pattern, use grep pattern /etc/passwd instead.

Resources