find-agent for OpenSSH

Kevin Buettner kev@primenet.com
Tue, 6 Jun 2000 17:27:37 -0700


As indicated in other email, I've recently installed OpenSSH 2.1.0p3
on several of my machines.

I will typically start an ssh-agent from a shell once I've started
my X11 session.  You typically invoke ssh-agent like this:

	eval `ssh-agent`
	ssh-add
	<you are then prompted for your passphrase>

I frequently want other shells to know about this authentication agent.
It is easy, though cumbersome to echo out the environment variables
and then export them to another shell.  It's much easier to use the
attached script as follows:

	eval `find-agent`

(Of course you can neatly circumvent the need for my script if you run
ssh-agent in the script which starts your X session.   This will cause
SSH_AUTH_SOCK and SSH_AGENT_PID to be set for all of the terminal
windows that you start from your X session.  But, for some reason that
I can't explain, I'd rather run it by hand.)

Kevin

--- find-agent ---
#!/usr/bin/perl -w

use English;

my @socknames = grep { -S && -o && -r } </tmp/ssh-*/agent.*>;

# Rank the sockets based upon their usefulness.  Some may also
# be weeded out along the way.  @ranks will hold elements of
# the form [N, Name] when done where N is the rank and Name is
# the name of the socket.
my @ranks = map { rank_socket($_) } @socknames;

# Sort in descending order based upon the rank
@ranks = sort { $b->[0] <=> $a->[0] } @ranks;

if (@ranks) {
    my $sockname = $ranks[0]->[1];
    my ($pidstart) = $sockname =~ m#/agent\.(\d+)$#;
    # Find the ssh-agent pids for the given user.
    my @pids = map { (split( /\s+/, $_, 4))[2] }
		   grep { /\d+\s+$UID\s+.*ssh-agent/ } `ps axl`;
    # Now find the pid closest to $pidstart (won't necessarily be correct)
    my $pid = shift @pids;
    foreach (@pids) {
	if (pid_goodness($pidstart, $_) < pid_goodness($pidstart, $pid)) {
	    $pid = $_;
	}
    }
    if (!defined($pid)) {
	print STDERR "No agent\n";
    }
    else {
	print STDOUT "SSH_AUTH_SOCK=$sockname; export SSH_AUTH_SOCK\n";
	print STDOUT "SSH_AGENT_PID=$pid; export SSH_AGENT_PID;\n";
	print STDERR "Agent pid $pid\n";
    }
}
else {
    print STDERR "No agent\n";
}


sub rank_socket {
    my ($sockname) = @_;
    return ()			unless -S $sockname;
    return ()			unless $sockname =~ m#/agent\.\d+$#;

    $ENV{SSH_AUTH_SOCK} = $sockname;
    my $retval = `ssh-add -l 2>&1`;
    delete $ENV{SSH_AUTH_SOCK};

    return () 			if $retval =~ /Could not connect/;
    return ([0, $sockname])	if $retval =~ /no identities/;
    my $n = 0;
    $n++			while ($retval =~ /\n/g);
    return ([$n, $sockname]);
}

sub pid_goodness {
    my ($pidstart, $pid) = @_;

    if ($pid >= $pidstart) {
	return $pid-$pidstart;
    }
    else {
	return $pid + 8000000;
    }
}
--- end find-agent ---