The mentioned syntax error was in this case item using Bash - linux

I am having difficulty to understand what I am doing wrong in the script. The purpose of the script is to grant or revoke access based on the parameters passed to the script.
#!/bin/bash
SERVER_IP_FILE=""
DEV_USER_KEY_FILE=""
USER=`whoami`
DEV_USER=""
MODE=""
showHelp() {
cat << EOF
...
EOF
}
grant_access()
{
while $line in `cat $SERVER_IP_FILE`
do
ssh $USER#$line sudo useradd $DEV_USER -d /home/$DEV_USER -G developer
ssh $USER#$line sudo mkdir /home/$DEV_USER/.ssh
ssh $USER#$line sudo touch /home/$DEV_USER/.ssh/authorized_keys
ssh $USER#$line sudo cat $DEV_USER_KEY_FILE > /home/$DEV_USER/.ssh/authorized_keys
ssh $USER#$line sudo chown -R $dev_user:$dev_user /home/$DEV_USER/.ssh
done
}
revoke_access()
{
while $line in `cat $SERVER_IP_FILE`
do
ssh $USER#$line sudo userdel $DEV_USER
ssh $USER#$line sudo rm -rf /home/$DEV_USER/.ssh
done
}
while getops "hfkum" opt; do
case "${opt}" in
-h|--help)
showHelp
# Shows help for running script.
;;
-f|--ip-file)
SERVER_IP_FILE=$opt
# File which contains IP addresses of server group.
;;
-k|--key-file)
DEV_USER_KEY_FILE=$opt
# Public key file of the user who's access needs to be granted or revoked
;;
-u|--user)
DEV_USER=$opt
# Username who needs to be granted access or revoked
;;
-m|--mode)
MODE=$opt
# Mode of operation. It must be either grant or revoke
;;
esac
done
shift $((OPTIND -1))
if [ $MODE == 'grant' ] ;
then
grant_access()
elif [ $MODE == 'revoke' ] ;
then
revoke_access()
else
echo "Wrong mode. Mode must be either grant or revoke"
fi
I am expecting to run script like below.
access.sh -m grant -f staging_server_ip.txt -k id_rsa.pub -u test-user
access.sh -m revoke -f staging_server_ip.txt -k id_rsa.pub -u test-user
and then it would do the desired operation. When I check script here
it gives me error on line 58, 59 and 62. I don't understand what I am doing wrong with syntax.

Use "bash -n myscript.sh" to test the syntax of your script.
In lines 81 and 84 you called functions with "()" which cause a syntax error.
Remove the "()" from lines 81 and 84 to fix your script's syntax:
if [ $MODE == 'grant' ] ;
then
grant_access
elif [ $MODE == 'revoke' ] ;
then
revoke_access
else
echo "Wrong mode. Mode must be either grant or revoke"
fi

Related

EOF and openssl passwd

I'm trying to make the following script in Ubuntu 11.
I'm a novice in this ... The script should receive parameters.
What I intend is, as a test, create two users, move a series of files, and assign a password by default, which will be the same login, and force change it once you log in.
I would like it to be encrypted, but I do not know how to pass that encrypted password to a command, for example to usermod -p, or assign a variable with the output of the command.
Since I do not get it, another option is to assign it with passwd using EOF so that it is not done interactively. So I use it in the way I indicated it, but I do not know how it is done that does not set the password I want.
Somebody can help me? Thank you very much
#!/bin/bash
usuario=`whoami`
if [ $usuario != "root" ]; then
echo El script tiene que ejecutarse con usuario root
exit 1
fi
if [ $# -lt 3 ]; then
echo NĂºmero de parĂ¡metros insuficiente
exit 2
fi
groupadd "$3"
useradd -m -g "$3" $1
useradd -m -G "$3" $2
echo " Usuarios y grupo creados "
cp /var/backups/* /home/"$1"
echo " Copia de backups realizada "
mv /home/"$1"/*bak /home/"$2"
passwd -e $1 && passwd $2<<EOF
$1
$1
$2
$2
EOF
#clave1=`openssl passwd -crypt "$1"`
#clave2=`openssl passwd -crypt "$2"`
#usermod -p clave1 $1
#usermod -p clave2 $2
#openssl passwd -crypt "$2" | usermod -p "$2" $2
The last 5 lines, are comments, rather attempts to create an encrypted key
Your best bet to pass the encrypted password to useradd.
You can get an encrypted password using the chpasswd command.
echo ":plaintextpassword" | chpasswd -S
The : is required as it separated a balnk user from the new password in the input to chpasswd.
Then everything after the : in the output that can be stored in the script and passed to useradd:
pwd='encryptedpasswd'
useradd -m -p "${pwd}" "${user}"

ssh to different nodes using shell scripting

I am using below code to ssh to different nodes and find if an user exists or not. If the user doesn't exist it will create it.
The script works fine if I don't do ssh but it fails if I do ssh.
How can I go through different nodes using this script?
for node in `nodes.txt`
usr=root
ssh $usr#$node
do
if [ $(id -u) -eq 0 ]; then
read -p "Enter username : " username
read -s -p "Enter password : " password
egrep "^$username" /etc/passwd >/dev/null
if [ $? -eq 0 ]; then
echo "$username exists!"
exit 1
else
pass=$(perl -e 'print crypt($ARGV[0], "password")' $password)
useradd -m -p $pass $username
[ $? -eq 0 ] && echo "User has been added to system!" || echo "F
ailed to add a user!"
fi
else
echo "Only root may add a user to the system"
exit 2
fi
done
Your script has grave syntax errors. I guess the for loop at the beginning is what you attempted to add but you totally broke the script in the process.
The syntax for looping over lines in a file is
while read -r line; do
.... # loop over "$line"
done <nodes.txt
(or marginally for line in $(cat nodes.txt); do ... but this has multiple issues; see http://mywiki.wooledge.org/DontReadLinesWithFor for details).
If the intent is to actually run the remainder of the script in the ssh you need to pass it to the ssh command. Something like this:
while read -r node; do
read -p "Enter user name: " username
read -p -s "Enter password: "
ssh root#"$node" "
# Note addition of -q option and trailing :
egrep -q '^$username:' /etc/passwd ||
useradd -m -p \"\$(perl -e 'print crypt(\$ARGV[0], \"password\")' \"$password\")" '$username'" </dev/null
done <nodes.txt
Granted, the command you pass to ssh can be arbitrarily complex, but you will want to avoid doing interactive I/O inside a root-privileged remote script, and generally make sure the remote command is as quiet and robust as possible.
The anti-pattern command; if [ $? -eq 0 ]; then ... is clumsy but very common. The purpose of if is to run a command and examine its result code, so this is better and more idiomatically written if command; then ... (which can be even more succinctly written command && ... or ! command || ... if you only need the then or the else part, respectively, of the full long-hand if/then/else structure).
Maybe you should only do the remote tasks via ssh. All the rest runs local.
ssh $user#$node egrep "^$username" /etc/passwd >/dev/null
and
ssh $user#$node useradd -m -p $pass $username
It might also be better to ask for username and password outside of the loop if you want to create the same user on all nodes.

How to check if ssh-agent is already running in bash?

I have a sample sh script on my Linux environment, which basically run's the ssh-agent for the current shell, adds a key to it and runs two git commands:
#!/bin/bash
eval "$(ssh-agent -s)"
ssh-add /home/duvdevan/.ssh/id_rsa
git -C /var/www/duvdevan/ reset --hard origin/master
git -C /var/www/duvdevan/ pull origin master
Script actually works fine, but every time I run it I get a new process so I think it might become a performance issue and I might end up having useless processes out there.
An example of the output:
Agent pid 12109
Identity added: /home/duvdevan/.ssh/custom_rsa (rsa w/o comment)
Also, along with all this, is it possible to find an existing ssh-agent process and add my keys into it?
No, really, how to check if ssh-agent is already running in bash?
Answers so far don't appear to answer the original question...
Here's what works for me:
if ps -p $SSH_AGENT_PID > /dev/null
then
echo "ssh-agent is already running"
# Do something knowing the pid exists, i.e. the process with $PID is running
else
eval `ssh-agent -s`
fi
This was taken from here
Also, along with all this, is it possible to find an existing ssh-agent process and add my keys into it?
Yes. We can store the connection info in a file:
# Ensure agent is running
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
# Could not open a connection to your authentication agent.
# Load stored agent connection info.
test -r ~/.ssh-agent && \
eval "$(<~/.ssh-agent)" >/dev/null
ssh-add -l &>/dev/null
if [ "$?" == 2 ]; then
# Start agent and store agent connection info.
(umask 066; ssh-agent > ~/.ssh-agent)
eval "$(<~/.ssh-agent)" >/dev/null
fi
fi
# Load identities
ssh-add -l &>/dev/null
if [ "$?" == 1 ]; then
# The agent has no identities.
# Time to add one.
ssh-add -t 4h
fi
This code is from pitfalls of ssh agents which describes both the pitfalls of what you're currently doing, of this approach, and how you should use ssh-ident to do this for you.
If you only want to run ssh-agent if it's not running and do nothing otherwise:
if [ $(ps ax | grep [s]sh-agent | wc -l) -gt 0 ] ; then
echo "ssh-agent is already running"
else
eval $(ssh-agent -s)
if [ "$(ssh-add -l)" == "The agent has no identities." ] ; then
ssh-add ~/.ssh/id_rsa
fi
# Don't leave extra agents around: kill it on exit. You may not want this part.
trap "ssh-agent -k" exit
fi
However, this doesn't ensure ssh-agent will be accessible (just because it's running doesn't mean we have $SSH_AGENT_PID for ssh-add to connect to).
If you want it to be killed right after the script exits, you can just add this after the eval line:
trap "kill $SSH_AGENT_PID" exit
Or:
trap "ssh-agent -k" exit
$SSH_AGENT_PID gets set in the eval of ssh-agent -s.
You should be able to find running ssh-agents by scanning through /tmp/ssh-* and reconstruct the SSH_AGENT variables from it (SSH_AUTH_SOCK and SSH_AGENT_PID).
ps -p $SSH_AGENT_PID > /dev/null || eval "$(ssh-agent -s)"
Single line command. Run for the first time will start ssh-agent. Run for the second time will not start the ssh-agent. Simple and Elegant Mate !!!
Using $SSH_AGENT_PID can only test the ssh-agent but miss identities when it is not yet added
$ eval `ssh-agent`
Agent pid 9906
$ echo $SSH_AGENT_PID
9906
$ ssh-add -l
The agent has no identities.
So it would be save to check it with ssh-add -l with an expect script like example below:
$ eval `ssh-agent -k`
Agent pid 9906 killed
$ ssh-add -l
Could not open a connection to your authentication agent.
$ ssh-add -l &>/dev/null
$ [[ "$?" == 2 ]] && eval `ssh-agent`
Agent pid 9547
$ ssh-add -l &>/dev/null
$ [[ "$?" == 1 ]] && expect $HOME/.ssh/agent
spawn ssh-add /home/user/.ssh/id_rsa
Enter passphrase for /home/user/.ssh/id_rsa:
Identity added: /home/user/.ssh/id_rsa (/home/user/.ssh/id_rsa)
$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)
So when both ssh-agent and ssh-add -l are put to run on a bash script:
#!/bin/bash
ssh-add -l &>/dev/null
[[ "$?" == 2 ]] && eval `ssh-agent`
ssh-add -l &>/dev/null
[[ "$?" == 1 ]] && expect $HOME/.ssh/agent
then it would always check and assuring that the connection is running:
$ ssh-add -l
4096 SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /home/user/.ssh/id_rsa (RSA)
You can also emulate the repeating of commands on above script with do while
The accepted answer did not work for me under Ubuntu 14.04.
The test to check if the ssh-agent is running I have to use is:
[[ ! -z ${SSH_AGENT_PID+x} ]]
And I am starting the ssh-agent with:
exec ssh-agent bash
Otherwise the SSH_AGENT_PID is not set.
The following seems to work under both Ubuntu 14.04 and 18.04.
#!/bin/bash
sshkey=id_rsa
# Check ssh-agent
if [[ ! -z ${SSH_AGENT_PID+x} ]]
then
echo "[OK] ssh-agent is already running with pid: "${SSH_AGENT_PID}
else
echo "Starting new ssh-agent..."
`exec ssh-agent bash`
echo "Started agent with pid: "${SSH_AGENT_PID}
fi
# Check ssh-key
if [[ $(ssh-add -L | grep ${sshkey} | wc -l) -gt 0 ]]
then
echo "[OK] SSH key already added to ssh-agent"
else
echo "Need to add SSH key to ssh-agent..."
# This should prompt for your passphrase
ssh-add ~/.ssh/${sshkey}
fi
Thanks to all the answers here. I've used this thread a few times over the years to tweak my approach. Wanted to share my current ssh-agent.sh checker/launcher script that works for me on Linux and OSX.
The following block is my $HOME/.bash.d/ssh-agent.sh
function check_ssh_agent() {
if [ -f $HOME/.ssh-agent ]; then
source $HOME/.ssh-agent > /dev/null
else
# no agent file
return 1
fi
if [[ ${OSTYPE//[0-9.]/} == 'darwin' ]]; then
ps -p $SSH_AGENT_PID > /dev/null
# gotcha: does not verify the PID is actually an ssh-agent
# just that the PID is running
return $?
fi
if [ -d /proc/$SSH_AGENT_PID/ ]; then
# verify PID dir is actually an agent
grep ssh-agent /proc/$SSH_AGENT_PID/cmdline > /dev/null 2> /dev/null;
if [ $? -eq 0 ]; then
# yep - that is an agent
return 0
else
# nope - that is something else reusing the PID
return 1
fi
else
# agent PID dir does not exist - dead agent
return 1
fi
}
function launch_ssh_agent() {
ssh-agent > $HOME/.ssh-agent
source $HOME/.ssh-agent
# load up all the pub keys
for I in $HOME/.ssh/*.pub ; do
echo adding ${I/.pub/}
ssh-add ${I/.pub/}
done
}
check_ssh_agent
if [ $? -eq 1 ];then
launch_ssh_agent
fi
I launch the above from my .bashrc using:
if [ -d $HOME/.bash.d ]; then
for I in $HOME/.bash.d/*.sh; do
source $I
done
fi
Hope this helps others get up and going quickly.
Created a public gist if you want to hack/improve this with me: https://gist.github.com/dayne/a97a258b487ed4d5e9777b61917f0a72
cat /usr/local/bin/ssh-agent-pro << 'EOF'
#!/usr/bin/env bash
SSH_AUTH_CONST_SOCK="/var/run/ssh-agent.sock"
if [[ x$(wc -w <<< $(pidof ssh-agent)) != x1 ]] || [[ ! -e ${SSH_AUTH_CONST_SOCK} ]]; then
kill -9 $(pidof ssh-agent) 2>/dev/null
rm -rf ${SSH_AUTH_CONST_SOCK}
ssh-agent -s -a ${SSH_AUTH_CONST_SOCK} 1>/dev/null
fi
echo "export SSH_AUTH_SOCK=${SSH_AUTH_CONST_SOCK}"
echo "export SSH_AGENT_PID=$(pidof ssh-agent)"
EOF
echo "eval \$(/usr/local/bin/ssh-agent-pro)" >> /etc/profile
. /etc/profile
then you can ssh-add xxxx once, you can use ssh-agent everytime when you login.
I've noticed that having a running agent is not enough because sometimes, the SSH_AUTH_SOCK variable is set or pointing to a socket file that does not exist anymore.
Therefore, to connect to an already running ssh-agent on your machine, you can do this :
$ pgrep -u $USER -n ssh-agent -a
1906647 ssh-agent -s
$ ssh-add -l
Could not open a connection to your authentication agent.
$ test -z "$SSH_AGENT_PID" && export SSH_AGENT_PID=$(pgrep -u $USER -n ssh-agent)
$ test -z "$SSH_AUTH_SOCK" && export SSH_AUTH_SOCK=$(ls /tmp/ssh-*/agent.$(($SSH_AGENT_PID-1)))
$ ssh-add -l
The agent has no identities.
Regarding finding running ssh-agents, previous answers either don't work or rely on a magic file like $HOME/.ssh_agent. These approaches require us to believe that user never run agents without saving their output to this file.
My approach instead relies on a rarely changed default UNIX domain socket template to find an accessible ssh-agent among available possibilities.
# (Paste the below code to your ~/.bash_profile and ~/.bashrc files)
C=$SSH_AUTH_SOCK
R=n/a
unset SSH_AUTH_SOCK
for s in $(ls $C /tmp/ssh-*/agent.* 2>/dev/null | sort -u) ; do
if SSH_AUTH_SOCK=$s ssh-add -l >/dev/null ; then R=$? ; else R=$? ; fi
case "$R" in
0|1) export SSH_AUTH_SOCK=$s ; break ;;
esac
done
if ! test -S "$SSH_AUTH_SOCK" ; then
eval $(ssh-agent -s)
unset SSH_AGENT_PID
R=1
fi
echo "Using $SSH_AUTH_SOCK"
if test "$R" = "1" ; then
ssh-add
fi
In this approach, SSH_AGENT_PID remains unknown, since it is hard to deduce it for non-roots. I assume it is actually not required for users since they don't normally want to stop agents. On my system, setting SSH_AUTH_SOCK is enough to communicate with agent for e.g. passwordless authentication.
The code should work with any shell-compatible shell.
You can modify line #1 to:
PID_SSH_AGENT=`eval ssh-agent -s | grep -Po "(?<=pid\ ).*(?=\;)"`
And then at the end of the script you can do:
kill -9 $PID_SSH_AGENT
I made this bash function to count and return the number of running ssh-agent processes... it searches ssh-agent process using procfs instead of using $ ps -p $SSH_AGENT_PID:cmd or $SSH_AUTH_SOCK:var ... (these ENV-var. can still be set with old values while ssh-agent's process is already killed: if $ ssh-agent -k or $ $(ssh-agent -k) instead of $ eval $(ssh-agent -k))
function count_agent_procfs(){
declare -a agent_list=( )
for folders in $(ls -d /proc/*[[:digit:]] | grep -v /proc/1$);do
fichier="${folders}/stat"
pid=${folders/\/proc\//}
[[ -f ${fichier} ]] && [[ $(cat ${fichier} | cut -d " " -f2) == "(ssh-agent)" ]] && agent_list+=(${pid})
done
return ${#agent_list[#]}
}
..and then if there is a lot of ssh-agent process running you get their PID with this list..."${agent_list[#]}"
Very simple command to check how many processes are running for ssh-agent (or any other program): pidof ssh-agent
or:
pgrep ssh-agent
And very simple command to kill all processes of ssh-agent (or any program):
kill $(pidof ssh-agent)

shell script ssh command not working

I have a small list of servers, and I am trying to add a user on each of these servers. I can ssh individually to each server and run the command.
sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
I wrote a script to loop through the list and run this command but I get some errors.
#!/bin/bash
read -p "Enter server list: " file
if [[ $file == *linux* ]]; then
for i in `cat $file`
do
echo "creating amurug on" $i
ssh $i sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
echo "==============================================="
sleep 5
done
fi
When I run the script it does not execute the command.
creating amurug on svr102
Usage: useradd [options] LOGIN
Options:
What is wrong with my ssh crommand in my script?
Try this script:
#!/bin/bash
read -p "Enter server list: " file
if [[ "$file" == *linux* ]]; then
while read -r server
do
echo "creating amurug on" "$server"
ssh -t -t "$server" "sudo /usr/sbin/useradd -c Arun -d /home/amurug \
-e 2014-12-12 -g users -u 1470 amurug"
echo "==============================================="
sleep 5
done < "$file"
fi
As per man bash:
-t
Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

Restarting apache without being superuser

Is there any possibility to perform graceful restart and check apache config syntax without being root or having root privileges?
I have already tried to set suid bit to the script which performs restart. Here is the script itself:
#!/bin/bash
FILENAME=$1
DATE=`date +%Y%m%d`
DIRECTORY='bckp/'
if [ ! -d "$DIRECTORY" ]; then
echo "Backup directory doesn't exist. Creating one."
mkdir $DIRECTORY
fi
if [ -z "$FILENAME" -a ! -f "$FILENAME" ]; then
FILENAME="webdav.conf"
echo "No file specified. Backing up webdav.conf"
fi
REV=0
BACKUP="$FILENAME.$DATE.$REV"
while [ -f $BACKUP ]; do
let REV+=1
BACKUP="$DIRECTORY$FILENAME.$DATE.$REV"
done
cp $FILENAME $BACKUP
echo $OUTPUT
OUTPUT=$(apache2ctl configtest 2>&1)
if [ "$OUTPUT" == "Syntax OK" ]; then
echo "Syntax OK"
echo "Performing restart"
apachectl -k graceful 2>&1
fi
exit $?
here is the ls -l for this file:
-rwsrwxr-x 1 root user 645 2012-04-26 18:05 graceful-restart
When i try to run this script i get the following output:
No file specified. Backing up webdav.conf
ulimit: 88: error setting limit (Operation not permitted) Syntax OK
I'm interested if it is possible to perform what i've described.
Linux will not honor the suid bit on a shell script. Read this for more information.
A common solution for this is the sudo command. With an entry like this in /etc/sudoers:
yourname ALL = NOPASSWD:/path/to/graceful-restart
You could run:
sudo /path/to/graceful-restart
And this would run with root privileges without prompting you for a password. See the sudoers man page for more information on the syntax of the sudoers file.

Resources