Mail Archives: cygwin/2002/08/01/08:57:36
Hello
There is a problem when running ssh-agent from a shell prompt: when you
logout from that shell the console window won't close until one kills
the agent.
The only solution that comes in mind is running ssh-agent as a service
(on Windows NT/2K platforms).
I've found two discussions on cygwin mailing list dedicated to this
subject here
http://www.cygwin.com/ml/cygwin-patches/2001-q1/msg00184.html
and here
http://www.cygwin.com/ml/cygwin/2002-05/msg01305.html,
but in the end I came with my own solution. Read on...
Starting an ssh-agent as a service is pretty easy:
cygrunsrv -I "ssh-agent-$USER" -d "CYGWIN ssh-agent for $USER" \
-p /usr/bin/ssh-agent -a "$S_OR_C_FLAG -d" \
-t manual -1 ~/.ssh-agent -o -u $USER
assuming the following requirements are met:
1) CYGWIN envronment variable contains ntsec option for valid socket permissions
2) A USER has "Log on as service" privilege
3) if cygrunsrv is run from startup script, a user, probably needs
administrative privileges to be able to install/start a service.
However, it is possible for a system administrator to install as many
instances of ssh-agent services as needed and configure them to start
automatically (see the "-t" option of cygrunsrv) during system boot,
thus not requiring additional priviliges for users other then "Log on
as service" (this is in theory, I have not tried this configuration).
Now, when we started an ssh-agent service the next problem is how
to carry the information about a socket, agent listens to, to
applications. We need to set SSH_AUTH_SOCK environment variable somehow.
The easy but not reliable way:
SSH_AUTH_SOCK=`find /tmp/ssh-* -type s -user $USER -perm 600 | tail -n 1`; export SSH_AUTH_SOCK
The reliable way to set SSH_AUTH_SOCK is only via ssh-agent output,
and this requires trivial patching of openssh sources. The problem is
that ssh-agent output to stdout is buffered, thus "-1 ~/.ssh-agent"
option of cygrunsrv makes empty file. Inserting call to fflush(stdout)
to the right place of ssh-agent.c (line 1070 for openssh-3.4p1,
before goto statement) does the trick.
The rest is pure shell scripting.
here is the patch
-8<----------------8<--------------8<--
diff -u openssh-3.4p1/ssh-agent.c openssh-3.4p1-patched/ssh-agent.c
--- openssh-3.4p1/ssh-agent.c 2002-06-26 05:19:13.000000000 +0600
+++ openssh-3.4p1-patched/ssh-agent.c 2002-07-31 14:09:16.000000000 +0600
@@ -1067,6 +1067,7 @@
printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
SSH_AUTHSOCKET_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)parent_pid);
+ fflush(stdout);
goto skip;
}
pid = fork();
-8<----------------8<--------------8<--
and the script I source from .bash_profile
it lacks one important feature - locking, to prevent simultanious
execution when several concurent consoles are starting
any ideas on how to implement it will be appreciated
-8<----------------8<--------------8<--
# start ssh-agent as a service and load private keys
unset SSH_AUTH_SOCK
unset SSH_AGENT_PID
SSH_AGENT=/usr/bin/ssh-agent
SSH_AGENT_OPT="-s -d"
SSH_AGENT_FILE="$HOME/.ssh-agent-$HOSTNAME"
SSH_ADD=/usr/bin/ssh-add
SSH_ADD_OPT=""
SSH_IDENTITIES=""
# Check for initial state:
# 1. there is only one instance of ssh-agent for the user
# 2. SSH_AGENT_FILE exists and the last string containing SSH_AUTH_SOCK
# matches running ssh-agent
# 3. the soket exists, its path matches ssh-agent's PID, and permissions are correct
#
# If any condition fails, reset to correct state:
# 1. kill all instances of ssh-agent
# 2. delete SSH_AGENT_FILE
# 3. start ssh-agent service and create new SSH_AGENT_FILE
#
# When correct initial state is achived, set and export SSH_AUTH_SOCK
# and SSH_AGENT_PID variables, add keys
ensure_ssh_agent_started()
{
if [ `ps x | grep 'ssh-agent$' | wc -l` -ne 1 -o ! -f "$SSH_AGENT_FILE" ] ; then
for pid in `ps x | awk '/ssh-agent$/ { print $1 }'` ; do
kill $pid
done
rm -f "$SSH_AGENT_FILE"
fi
if [ `ps x | grep 'ssh-agent$' | wc -l` -eq 0 ] ; then
echo Installing service ssh-agent-$USER...
# this command will ask you for a user password
# it is required to install the service that runs on
# behalf of a user
cygrunsrv -I "ssh-agent-$USER" -d "CYGWIN ssh-agent for $USER" \
-p "$SSH_AGENT" -a "$SSH_AGENT_OPT" -t manual -u "$USER" \
-o -1 "$SSH_AGENT_FILE"
echo Starting service ssh-agent-$USER...
if ! cygrunsrv -S "ssh-agent-$USER" ; then
echo Failed to start ssh-agent-$USER service
return 1
else
SSH_AGENT_STARTED=1
fi
fi
return 0
}
validate_ssh_agent_and_load_keys()
{
SSH_AGENT_PID=`ps x | awk '/ssh-agent$/ { print $1 }'`
eval `grep '^SSH_AUTH_SOCK' "$SSH_AGENT_FILE" 2>/dev/null | tail -n 1`
if test -n "$SSH_AGENT_PID" -a -n "$SSH_AUTH_SOCK" &&
expr match "$SSH_AUTH_SOCK" "/tmp/ssh-[A-Za-z]*$SSH_AGENT_PID/agent.$SSH_AGENT_PID" 1>/dev/null &&
find `dirname $SSH_AUTH_SOCK` -type s -perm 600 -user "$USER" 1>/dev/null 2>/dev/null ; then
export SSH_AGENT_PID
if [ -n "$SSH_AGENT_STARTED" ] ; then
echo Adding keys to the agent
$SSH_ADD $SSH_ADD_OPT $SSH_IDENTITIES
fi
else
unset SSH_AUTH_SOCK
unset SSH_AGENT_PID
fi
}
ensure_ssh_agent_started && validate_ssh_agent_and_load_keys
unset ensure_ssh_agent_started
unset validate_ssh_agent_and_load_keys
unset SSH_AGENT
unset SSH_AGENT_OPT
unset SSH_AGENT_FILE
unset SSH_ADD
unset SSH_ADD_OPT
unset SSH_IDENTITIES
unset SSH_AGENT_STARTED
-8<----------------8<--------------8<--
--
Best regards,
Boris
--
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html
Documentation: http://cygwin.com/docs.html
FAQ: http://cygwin.com/faq/
- Raw text -