#!/bin/sh # #### # Copyright (c), 2001, 2002, 2003 gabriel rosenkoetter. # # Feel free to use, modify, and redistribute this. I'm not silly # enough to imagine that this is hard enough that someone else # wouldn't come up with it originally, but do me the favor of leaving # my copyright notice if you're just handing my script around. Thanks. #### # usage: # # agent-keeper [program] # # ... where [program] is whatever you want to have a conception of # your ssh-agent (if you leave it blank, ${SHELL} will be used). # # If there's no ssh-agent running, it wasn't agent-keeper that started # the existing ssh-agent(s), or ${AF} references a stale ssh-agent # (that is, the ${SSH_AUTH_SOCK} listed in it doesn't reference a # useable named socket), a new ssh-agent is started and ssh-add is # fed ${KEYS} (it will ask you for passphrases if your keys need # them; with a proper ssh-add implementation, it will launch # x11-ssh-askpass or similar to get the keys when it doesn't have a # useable tty, as it won't if you've done all this from your X11, # OpenWindows, whatever setup). # # If, on the other hand, an existing ssh-agent is found, the correct # ${ENV} settings are made and handed to the child of agent-keeper. # (This is by far the more usual case.) # # You're likely to want to change the ${SHELL} and ${KEYS} settings, # you might as well leave ${AF} alone as long as it doesn't collide # with other software you're using. # XXX CL flags for these? SHELL=${SHELL:=`which zsh`} KEYS="" AF=${HOME}/.ssh-agent # You probably don't need to change anything below this. # We're going to need to verify that an ssh-agent process is # running. First, we'll hope that we're on a POSIX system sporting a # pgrep(1). Then, we'll hope that a /proc file system exists, since, # though they're wildly different, they all have /proc/, which is # all we actually care about. Then, shit gets ugly as we try to # figure out what kind of ps(1) we're using, since we must pass it a # flag--different for BSD than for SysV--to display all running # processes, as we've got no reason to assume that it'll show up in # just an argument-free ps, since the chances of the ssh-agent we # want being in the same family tree as us are slim to none. # # XXX moved below till I can remember how to evaluate variables in # a string in sh later, but not immediately. if [ "x$1" = "x" ]; then EXEC="exec ${SHELL}" else EXEC="exec $@" fi if [ -f ${AF} ]; then # We've got a stored agent file... eval `cat ${AF}` # XXX move me back up if [ `which pgrep` ] ; then # Things are *very* easy. And POSIX. Good job, `uname -s`. Bravo. # # XXX This isn't perfect: so there's a process with the right pid and # it's called 'ssh-agent', and we even have files in /tmp/ssh # that point at it... but we don't know that we actually own the # running process. Check that. PSTEST=`pgrep ssh-agent | grep ${SSH_AGENT_PID}` elif [ -d /proc/$$ ] ; then # Good, we'll still have an easy time of this, since we can just # verify the existence of a /proc directory for the ssh-agent process. # ($$ is "my pid") # # XXX This is even *less* perfect. All we know is that there's a # process with the right pid running; we don't even know what it's # called without digging through /proc/'s files a bit. PSTEST="-d /proc/${SSH_AGENT_PID}" else # XXX If neither of these works, we've got a hard problem. Solve # it later. :^> # # XXX Perfect! Hah! PSTEST='``' fi # XXX move me back up if [ -r ${SSH_AUTH_SOCK} \ -a -S ${SSH_AUTH_SOCK} \ -a -O ${SSH_AUTH_SOCK} \ -a ${PSTEST} ]; then # ... and it seems to apply to a useful ssh-agent... if [ "x`ssh-add -l`" != 'xThe agent has no identities.' ] ; then # XXX generalize me at least through variable setting for # other SECSH implementations. # # ... and it even has valid keys unlocked. ${EXEC} # XXX Can we find a way to make sure it's got valid keys unlocked # that we actually want? else # ... but that agent doesn't have any keys unlocked. So we'll # just add the keys and go. echo "Valid agent running, but it has no keys unlocked." ssh-add ${KEYS} ${EXEC} fi else # ... but the ssh-agent it references is no good, so we # effectively start from scratch. Cleaning up the /tmp/ssh* # directory here *might* be a good idea, but automated rm(1)s # are scary, often open to timing attacks, so we'll leave it # alone. echo "Stale agent file, ${AF}." fi else # No stored agent file, so we'll start from scratch. echo "No existing agent file, looking for ${AF}." fi # Didn't find an extant, working ssh-agent socket ssh-agent > ${AF} eval `cat ${AF}` ssh-add ${KEYS} ${EXEC}