With X11 on my Linux desktop, ssh-agent works quite nicely with each new window getting access to my passwordless access keys automatically. But when I ssh in from home (or elsewhere), I don't get the X11 ssh-agent configuration. And even starting screen(1) with those environment variables set doesn't result in new screen windows created after I reconnect inheriting them.
So I ran into some sample bash code for setting up a single ssh-agent per machine that each new shell gets access to automatically (minor security weakening there that I don't think bothers me much, especially now that I added support for setting a maximum lifetime for identities that you add). I made some improvements to it and then decided that porting it to Win32 would be great because ssh-agent was awkward to use on Win32 (where I use cygwin's ssh and scp all the time).
I started porting it as a *.bat (or *.cmd) script. But there is some trick for allowing a *.bat/*.cmd script to call another *.bat/*.cmd script such that "SET" commands in the nested script impact the environment of the original cmd.exe shell and I couldn't remember what that trick was. So I just converted the whole thing to Perl instead.
I'm very happy with the results. Corion prompted me into looking at "help cmd" where I found a registry key that will cause my creation to be run automatically for each new cmd.exe window that I open. Now my single ssh-agent is set up automatically for me every time.
I tried to think of a name that represented something that keeps track of my ssh-agent(s) for me, a framework that is more persistant, so "ssh-agency" seemed a logical choice. But I found typing "ssh-agency" was too similar to "ssh-agent" so I just call it "agency". Not that I have to even type "agency" again after I run this one-liner:
perl -MWin32::TieRegistry=Delimiter,/ -e"$Registry->{'CUser/Software/M +icrosoft/Command Processor//AutoRun'}= 'agency -t 12h';"
(agency.bat needs to be in your %PATH%, shown below:)
@rem = '--*-Perl-*-- @echo off if "%OS%" == "Windows_NT" goto WinNT perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofperl :WinNT perl -x -S %0 %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl if %errorlevel% == 9009 echo You do not have Perl in your PATH. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul goto endofperl @rem '; #!/usr/bin/perl -w #line 15 use strict; # Since perl last read DATA w/o binmode, this value could be a byte or + few # too high. So we call tell() before reading from <DATA>... (see belo +w) my $pos= tell( DATA ) or die "Can't tell(DATA): $!\n"; my $label= <DATA>.'' or die "Found no label in DATA\n"; my @env= <DATA>; my( $pid )= map { $ENV{$1}= $2 if /(\w+)=([^\r\n]*)/; /PID=(\d+)/; } @env; if( $pid && kill 0, $pid ) { for my $line ( qx< ssh-add -l > ) { if( $line =~ /^\d/ ) { printf "Using %s\n", ( split ' ', $line )[2]; } else { print $line; } } exit; } @env= grep { if( s{(\w+)=([^;]+);.*}{set $1=$2\r} ) { $ENV{$1}= $2; 1; } else { 0; } } qx< ssh-agent @ARGV >; system( "ssh-add" ); open DATA, "+<", $0 or die "Can't re-open $0: $!\n"; binmode DATA or warn "re-binmode DATA failed: $!\n"; # ...(see above) Seek to the start of the ":endofperl" label, or perha +ps a few # bytes past the start of it due to non-binmode reading of DATA by per +l... seek( DATA, $pos, 0 ) or die "Can't seek DATA: $!\n"; # ... read to the end of the label /in binmode/ so tell() will be exac +t. $label= <DATA>; seek( DATA, 0, 1 ) or die "Can't re-seek DATA: $!\n"; print DATA @env; $pos= tell( DATA ) or die "Can't re-tell(DATA): $!\n"; truncate( DATA, $pos ) or die "Can't truncate DATA: $!\n"; __END__ :endofperl
If you manage to open a window without Agency running, then just type "agency" whenever you want. If there isn't already an ssh-agent running, then it will start one and then run "ssh-add" which will prompt you for your passphrase(s) for your default private key(s) (and will leave your current shell with the environment variables set so ssh and scp use your keys passwordlessly) or just press <ENTER> and you won't be prompted for passwords again even when "agency" gets run again.
Every time you run "agency" after that, you will be shown the list of identities that you can use passwordlessly now. Just use "ssh-add" to add more identities. Run "ssh-agent -k" if you want to just shut down your global ssh-agent.
I wish "ssh-add -t 8h" would expire an identity 8 hours after the last time I made use of it, instead of 8 hours after I added it. But "-t 12h" is a nice compromise, considering (or just leave off "-t ..." and have your identities last 'forever').
Since this Perl code only works on Win32, here is the bash code I added to my .bashrc file:
# Persist our ssh-agent settings to each shell we open: ssh_env="$HOME/.ssh/agent.env" if [ -f "$ssh_env" ]; then . "$ssh_env" if kill -CONT $SSH_AGENT_PID 2>/dev/null; then ssh-add -l | awk '{ if($5){ print }else{ print "Using",$3 } }' else rm "$ssh_env" fi fi if [ ! -f "$ssh_env" ]; then echo "Restarting ssh-agent; run ssh-add." > "$ssh_env" chmod 600 "$ssh_env" if [ -s "$ssh_env" ]; then mv "$ssh_env" "$ssh_env.$$" echo "Somebody raced a hack into $ssh_env.$$ !" 1>&2 else ssh-agent | sed -e 's/^echo/#echo/' >> "$ssh_env" . "$ssh_env" fi fi
Enjoy!
- tye
|
|---|