Skip to content

Instantly share code, notes, and snippets.

@cppcooper
Last active February 17, 2023 21:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cppcooper/7a0467b5cdb3fb3ba468144be3a76a0c to your computer and use it in GitHub Desktop.
Save cppcooper/7a0467b5cdb3fb3ba468144be3a76a0c to your computer and use it in GitHub Desktop.
Attach ssh-agent to multiple terminals
#!/usr/bin/bash
windows() { [[ -n "$WINDIR" ]]; }
if ! windows; then
lock="/tmp/.lock-sshbash"
exec 3>$lock
flock --timeout 300 3 || exit 1
fi
get-agents() {
if windows; then
tasklist //V | grep ssh-agent | grep $(whoami)
else
ps x | grep ssh-agent | grep -v grep
fi
}
get-pid() {
if windows; then
awk '{print $2}'
else
awk '{print $1}'
fi
}
kill-ssh-agent(){
for pid in $(get-agents | get-pid)
do
if windows; then
taskkill //F //PID $pid
else
kill $pid
fi
done
}
print-ssh-connection-info(){
echo $SSH_AUTH_SOCK
if windows;then
echo Agent winpid $(ps | grep $SSH_AGENT_PID | grep -v grep | awk '{print $4}')
fi
echo Agent pid $SSH_AGENT_PID
echo Active keys
echo -----------
ssh-add -l
}
connect-ssh-agent(){
if [ -f ~/.ssh/agent.sh ]
then
debug_ "running agent.sh"
. ~/.ssh/agent.sh 2>&1 >/dev/null
#print-ssh-connection-info
else
debug_ "agent.sh doesn't exist"
touch ~/.ssh/agent.sh
#echo "Critical Error: ~/.ssh/agent.sh does not exist"
fi
}
start-ssh-agent(){
debug_ "start_ssh_agent arguments: '$@'"
if [[ "$@" != '--keep' ]]
then
debug_ "killing existing agents"
if [[ "$@" == '--silent' ]]
then
kill-ssh-agent &> /dev/null
else
kill-ssh-agent
fi
else
debug_ "keeping existing agents"
fi
ssh-agent > ~/.ssh/agent.sh
connect-ssh-agent #run it
reformat-agentsh
}
reformat-agentsh(){
Line1="SSH_AUTH_SOCK=$SSH_AUTH_SOCK; export SSH_AUTH_SOCK;"
Line2="SSH_AGENT_PID=$SSH_AGENT_PID; export SSH_AGENT_PID;"
if windows
then
export SSH_AGENT_WINPID=$(ps | grep $SSH_AGENT_PID | grep -v grep | awk '{print $4}')
Line3="SSH_AGENT_WINPID=$SSH_AGENT_WINPID; export SSH_AGENT_WINPID;"
fi
Line4="echo Agent winpid $SSH_AGENT_WINPID;"
Line5="echo Agent pid $SSH_AGENT_PID;"
debug_ "$Line1\n$Line2\n$Line3\n$Line4\n$Line5\n"
printf "$Line1\n$Line2\n$Line3\n$Line4\n$Line5\n" > ~/.ssh/agent.sh
}
debug_ "debug mode on"
if [ -z "$CYGWIN_SHELL" ] && [ -z "$MSYS_SHELL" ]
then
sshcount=0
# To ensure we connect across ttys and even if we didn't run it at the tty level
# we need to check a number of things. (and that it works on windows)
# Check:
# that there is at least one agent running
# that the running agent is referenced inside agent.sh
# If it is not the agent referenced inside agent.sh the user may have multiple running
for pid in $(get-agents | get-pid)
do
((sshcount++))
done
debug_ "ssh-agent count: $sshcount"
if ((sshcount == 0))
then
# Start agent
debug_ "user has no ssh-agents open"
start-ssh-agent --keep
#--keep micro-optimization
else
# Connect to existing agent
debug_ "attempting to connect to the ssh-agent referenced inside agent.sh"
connect-ssh-agent 1> /dev/null
# we want to display the connection info at the end, so we save it
if ssh-add -l 2>&1 | grep "Error" &> /dev/null
then
# Start agent after failed connection attempt
debug_ "ssh agent not connected or started"
start-ssh-agent 1> /dev/null
elif windows
then
# Windows? this probably doesn't work
debug_ "Okay, we are connected to an agent but let's check that it is the PID inside agent.sh"
PID=0
for pid in $(get-agents | get-pid)
do
if [[ $pid == $SSH_AGENT_WINPID ]]
then
debug_ "PID from agent.sh is running"
PID=$pid
break
fi
done
if ((PID == 0))
then
debug_ "Could not find PID from agent.sh"
start-ssh-agent --keep 1> /dev/null
fi
fi
print-ssh-connection-info
fi
fi
if ! windows; then
rm -rf $lock
flock -u 3
fi
#unset -f get-agents
#unset -f get-pid
@cppcooper
Copy link
Author

cppcooper commented Dec 28, 2019

Works on Windows(git for windows bash) and Linux.

Uses functions from functions.bash
functions used:

  • newlock
  • releaselock
  • blockon
  • debug_ sort of.. usually it is disabled so..

Intended to be loaded in .bashrc to connect your terminal(s) to an existing ssh-agent's which must have been started by this script.

Adds functions for easy command line intervention.

  • kill-ssh-agent (kills all you own)
  • start-ssh-agent (starts an ssh-agent, also prepares and saves ~/.ssh/agent.sh for other terminals to use.)
  • connect-ssh-agent (connects terminals to the most recent started ssh-agent [via start-ssh-agent])
  • rewrite-agentsh intended for in script use. This is needed on windows to ensure future terminals can find the ssh-agent running

On windows the PID reported in the ssh-agent output will not match what the windows task manager sees, or process explorer. It will match what ps sees however, which also reports the WINPID.. so the script finds the WINPID via the PID and saves it to the ~/.ssh/agent.sh script, along with the other ssh-agent output.

I almost wrote an issue in the git for windows issue tracker, until I realized the PID was matching the ps outputted PID. It was quite concerning when ssh-agent wasn't detecting the correct PID. Then I realized bash was providing a PID and WINPID. I initially switched to just using the PID for bash, but had a bug pop up where it couldn't find the PID after having closed Cmder/ConEmu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment