d3227931e2
first solution was one tempfile for all connections there have been probably problems, when more connections have been startet at the same time. on write pubkeys, while the other tried to read the file.
407 lines
17 KiB
Bash
Executable file
407 lines
17 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# loggerfactory
|
|
LANG=C
|
|
for f in logerror logwarn loginfo logdebug logtrace ENTRY EXIT SCRIPTENTRY SCRIPTEXIT; do
|
|
if LANG=C type -t $f 2> /dev/null| grep -q 'function'; then
|
|
:
|
|
else
|
|
fx=${f//log/}
|
|
echo create function $f for $fx >&2
|
|
eval "$f () { \
|
|
local loglevels; \
|
|
declare -a loglevels; \
|
|
case $fx in
|
|
error)
|
|
loglevels=()
|
|
;;
|
|
warn)
|
|
loglevels=(\"ERROR\")
|
|
;;
|
|
info)
|
|
loglevels=(\"ERROR\" \"WARN\" )
|
|
;;
|
|
debug)
|
|
loglevels=( \"ERROR\" \"WARN\" \"INFO\" )
|
|
;;
|
|
trace|ENTRY|EXIT|SCRIPTENTRY|SCRIPTEXIT)
|
|
loglevels=( \"ERROR\" \"WARN\" \"INFO\" \"DEBUG\" )
|
|
;;
|
|
esac
|
|
if [[ ! \${loglevels[*]} =~ \"\${LOGLEVEL-\${LOGLEVEL_DEFAULT}}\" ]];then \
|
|
echo "\$@" >&2
|
|
fi; \
|
|
}"
|
|
unset fx
|
|
fi
|
|
done
|
|
unset f
|
|
|
|
usage(){
|
|
cat << EOF
|
|
|
|
Usage: ssh-agent-start-or-restart [[-c]|[--create-only]]|[[-t]|[--token-only]]|[[-k]|[--key-only]]|[[-r]|[-f]|[--readd]|[--force]] [<ssh-identity>]
|
|
|
|
If started only with <ssh-identity>, the script looks up in configured identity-path \$SSH_IDENTITIES_DIR (${SSH_IDENTITIES_DIR}) if it can find a directory named after <ssh-identity>.
|
|
If no <ssh_identity> is given, the identity is set to \$SSH_DEFAULT_IDENTITY ($SSH_DEFAULT_IDENTITY) configured via Environment.
|
|
IF \$SSH_DEFAULT_IDENTITY is also not set, default is the SSH_DEFAULT_IDENTITY
|
|
|
|
The output is the name of the file, where ssh-agent infomations are hold to load it to current shell for further actions.
|
|
Use "$ eval \$(<outputfilenam>)", if you want to load the SSH_AUTH_SOCK and SSH_AGENT_PID in current shell or shorter "$ loadagent [<ssh_identity>]"
|
|
|
|
-c|--create-only Create or restart only the agent. Do not load any
|
|
key or token in it.
|
|
The Output is used for loading the agent in the current
|
|
shell. (loadagent <identity>)
|
|
-t|--token-only To add or renew only configured pkcs11-hardware-token
|
|
configured in ${SSH_IDENTITIES_DIR}/<ssh-identity>,
|
|
just use this.
|
|
-k|--key-only To add or renew only configured keys configured in
|
|
${SSH_IDENTITIES_DIR}/<ssh-identity>, just use this.
|
|
-r|-f|--readd-token|--force remove all in ${SSH_IDENTITIES_DIR}/<ssh-identity>
|
|
configured keys and tokens and readd them again.
|
|
Depends on -t an -k Option to select wheter only
|
|
keys or tokens only. If no -t and -k is given, all
|
|
keys and token are removed and readded again.
|
|
Just to be asked for password again, if you plugged off
|
|
hardware-token and plugged it in again.
|
|
--rm|--remove remove keys and token instead of adding them.
|
|
-h|--info Show this info
|
|
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
check_token(){
|
|
|
|
# it's the same as in functions.sh
|
|
# defined here also, to work also in environments, where functions.sh couldn't be sourced
|
|
[ -z "${P11M:+x}" ] && { P11M=$PKCS11_MODULE; export P11M; }
|
|
|
|
# If DISPLAY is set, ssh-add calls ssh-askpass, and if its in remote-terminal, it wont work
|
|
# So remember and unset DISPLAY, and set it at the end again, if it was set before
|
|
[ $DISPLAY ] && local DISPLAY_ORIG=$DISPLAY
|
|
[ $DISPLAY ] && logtrace "unset DISPLAY: $DISPLAY"
|
|
[ $DISPLAY ] && unset DISPLAY
|
|
|
|
# Write public keys of all in agent stored keys to a temporary file
|
|
local tmppubkey="$(mktemp -p ${XDG_RUNTIME_DIR} pubkey.XXXXXX.pub)"
|
|
logtrace "tmppubkey: $tmppubkey"
|
|
loginfo "$(ssh-add -L > $tmppubkey)"
|
|
# Check if public-keys in tmppubkey are working. They are not working, if you removed and add back hardware-token.
|
|
loginfo "$(ssh-add -T ${tmppubkey}|| { ssh-add -e $P11M; ssh-add -s $P11M; } )"
|
|
logdebug "$(rm "${tmppubkey}")"
|
|
loginfo "$(ssh-add -l )"
|
|
[ $DISPLAY_ORIG ] && logtrace "reset DISPLAY=$DISPLAY_ORIG"
|
|
[ $DISPLAY_ORIG ] && export DISPLAY=$DISPLAY_ORIG
|
|
|
|
}
|
|
|
|
createonly=false
|
|
tokenonly=false
|
|
readd=false
|
|
keyonly=false
|
|
remove=false
|
|
while :; do
|
|
case $1 in
|
|
-c|--create-only)
|
|
createonly=true
|
|
shift
|
|
;;
|
|
-t|--token-only)
|
|
tokenonly=true
|
|
shift
|
|
;;
|
|
-k|--key-only)
|
|
keyonly=true
|
|
shift
|
|
;;
|
|
-r|-f|--readd-token|--force)
|
|
readd=true
|
|
shift
|
|
;;
|
|
--rm|--remove)
|
|
remove=true
|
|
shift
|
|
;;
|
|
-h|--info)
|
|
usage
|
|
exit 0
|
|
;;
|
|
-*)
|
|
echo "Unknown urgument: »$1«"
|
|
exit 1
|
|
;;
|
|
*)
|
|
#ssh_identity=${1-${SSH_DEFAULT_IDENTITY}}
|
|
ssh_identity=${1}
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
SCRIPTENTRY
|
|
[ -z "${SSH_IDENTITIES_DIR+x}" ] && { SSH_IDENTITIES_DIR="${SSH_IDENTITIES_DEFAULT_DIR-${HOME}/.ssh/identities}"; export SSH_IDENTITIES_DIR; }
|
|
[ -z "${SSH_AGENTS_DIR+x}" ] && { SSH_AGENTS_DIR=${SSH_AGENTS_DEFAULT_DIR-~/.ssh/agents}; export SSH_AGENTS_DIR; }
|
|
[ -z "${SSH_AGENT_SOCKETS_DIR+x}" ] && { SSH_AGENT_SOCKETS_DIR=${SSH_AGENT_SOCKETS_DEFAULT_DIR-~/.ssh/agents}; export SSH_AGENT_SOCKETS_DIR; }
|
|
[ -z "${SSH_AGENT_OPTIONS+x}" ] && { SSH_AGENT_OPTIONS=${SSH_AGENT_DEFAULT_OPTIONS--t 7200 }; export SSH_AGENT_OPTIONS; }
|
|
logtrace " SSH_AGENTS_DIR: $SSH_AGENTS_DIR"
|
|
logtrace "SSH_AGENT_SOCKETS_DIR: $SSH_AGENT_SOCKETS_DIR"
|
|
logtrace " SSH_IDENTITIES_DIR: $SSH_IDENTITIES_DIR"
|
|
[ -z "${SSH_AGENTS_DIR-x}" ] || mkdir -vp "$SSH_AGENTS_DIR"
|
|
[ -z "${SSH_AGENT_SOCKETS_DIR-x}" ] || mkdir -vp "$SSH_AGENT_SOCKETS_DIR"
|
|
[ -z "${SSH_IDENTITIES_DIR-x}" ] || mkdir -vp "$SSH_IDENTITIES_DIR"
|
|
|
|
|
|
agent-start-or-restart () {
|
|
|
|
ENTRY
|
|
local ssh_identity
|
|
local agentfile
|
|
local agentsocket
|
|
local ret
|
|
|
|
if [ -n "${1+x}" ]; then
|
|
ssh_identity="${1}"
|
|
identitydir=${SSH_IDENTITIES_DIR}/${ssh_identity}
|
|
loginfo "ssh-identität: ${ssh_identity}" >&2
|
|
if [ -d ${identitydir} ]; then
|
|
[ -e "${identitydir}/config" ] && . "${identitydir}/config"
|
|
agentfile="${SSH_AGENTS_DIR}/agent-${ssh_identity}-$(hostname)"
|
|
agentsocket="${SSH_AGENT_SOCKETS_DIR}/socket-${ssh_identity}-$(hostname)"
|
|
logtrace "agentfile for ${ssh_identity}: $agentfile"
|
|
logtrace "agentsocket for ${ssh_identity}: $agentsocket"
|
|
if (! $keyonly && ! $tokenonly ) && $remove ; then
|
|
logdebug "delete keys and tokens in this ssh-agent"
|
|
logdebug "$(ssh-runinagent $agentfile ssh-add -D 2>&1)"
|
|
createonly=true
|
|
|
|
else
|
|
if [ -e $agentfile ]; then
|
|
|
|
local msg
|
|
# TODO make in runinagent
|
|
msg="$(/bin/sh -c "unset SSH_AUTH_SOCK SSH_AGENT_PID; . $agentfile >/dev/null 2>&1; ssh-add -l 2>&1")"
|
|
local ret=$?
|
|
logtrace "Output from check for running: $msg"
|
|
case $ret in
|
|
0)
|
|
logdebug "agent is running"
|
|
;;
|
|
1)
|
|
logdebug "agent is running, but:"
|
|
logwarn "$msg"
|
|
;;
|
|
2)
|
|
logdebug "former agent is not running -> start it"
|
|
logdebug "SSH_AGENT_OPTIONS: $SSH_AGENT_OPTIONS"
|
|
[ -e $agentsocket ] && { logdebug -n "remove socketfile: $( rm -v "$agentsocket" )"; }
|
|
logtrace "$(ssh-agent -a $agentsocket ${SSH_AGENT_OPTIONS} > $agentfile )"
|
|
logdebug "agent started"
|
|
;;
|
|
esac
|
|
else
|
|
logdebug "agent did not exist -> create it"
|
|
logtrace "ssh-agent -a $agentsocket \> $agentfile"
|
|
logtrace "$(ssh-agent -a $agentsocket $SSH_AGENT_OPTIONS > $agentfile )"
|
|
logdebug "agent started"
|
|
fi
|
|
fi
|
|
|
|
#logdebug "ssh-agent for identity »$ssh_identity«: $agentfile"
|
|
$createonly && logtrace "current loaded keys after action:
|
|
$(ssh-runinagent $agentfile ssh-add -l)"
|
|
echo $agentfile
|
|
ret=0
|
|
else
|
|
logwarn "ssh-identity »$ssh_identity« is not configured. Please create $identitydir and add keys"
|
|
ret=2
|
|
fi
|
|
|
|
else
|
|
|
|
if which gnome-keyring-daemon >/dev/null 2>&1; then
|
|
logdebug "no identity given -> gnome-keyrings ssh-agent"
|
|
agentfile="${SSH_AGENTS_DIR}/agent-gnome_session-$(hostname)"
|
|
agentsocket="${SSH_AGENT_SOCKETS_DIR}/socket-gnome-session-$(hostname)"
|
|
gnome-keyring-daemon -s > $agentfile
|
|
logdebug "$(cat $agentfile)"
|
|
logdebug "ssh-agent for identity »$ssh_identity«: $agentfile"
|
|
# logdebug "currently loaded keys after action:
|
|
#$(ssh-runinagent $agentfile ssh-add -l)"
|
|
echo $agentfile
|
|
ret=0
|
|
else
|
|
logwarn "no identity given -> exit"
|
|
ret=1
|
|
fi
|
|
|
|
fi
|
|
|
|
EXIT
|
|
return $ret
|
|
|
|
}
|
|
|
|
agent-load-identity-keys () {
|
|
|
|
ENTRY
|
|
local ssh_identity
|
|
local agentfile
|
|
local agentsocket
|
|
local fingerprints
|
|
declare -a fingerprints
|
|
local pubkeysonly
|
|
declare -a pubkeysonly
|
|
local fingerprint
|
|
local tokenfingerprint
|
|
|
|
if [ -n "${1+x}" ]; then
|
|
ssh_identity="${1}"
|
|
identitydir=${SSH_IDENTITIES_DIR}/${ssh_identity}
|
|
if [ -d ${identitydir} ]; then
|
|
[ -e "${identitydir}/config" ] && . "${identitydir}/config"
|
|
agentfile="${SSH_AGENTS_DIR}/agent-${ssh_identity}-$(hostname)"
|
|
agentsocket="${SSH_AGENT_SOCKETS_DIR}/socket-${ssh_identity}-$(hostname)"
|
|
logdebug "SSH_ADD_OPTIONS: $SSH_ADD_OPTIONS"
|
|
logtrace "agentfile: $agentfile"
|
|
logtrace "agentsocket: $agentsocket"
|
|
logtrace "identitydir: $identitydir"
|
|
|
|
fingerprints=( $(ssh-runinagent $agentfile "ssh-add -l|awk '{print \$2}'") )
|
|
logdebug "fingerprints from loaded keys before action:"
|
|
for f in ${fingerprints[*]};do
|
|
logdebug "$f"
|
|
done
|
|
if ! $tokenonly ; then
|
|
# load keys
|
|
for key in $(ls ${SSH_IDENTITIES_DIR}/${ssh_identity}/id_*|grep -v "pub$\|so$\|config$\|public$"); do
|
|
fingerprint=$(ssh-keygen -l -f $key|awk '{print $2}')
|
|
if [[ ${fingerprints[*]} =~ "$fingerprint" ]]; then
|
|
logdebug "key: $(basename $key) (with fp $fingerprint) is loaded"
|
|
if $readd || $remove ; then
|
|
$readd && logdebug "re-add key $key"
|
|
$remove && logdebug "remove key $key"
|
|
logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} -d ${key} 2>&1)"
|
|
$remove || logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} ${key} 2>&1)"
|
|
fi
|
|
else
|
|
logdebug "key: $key is not loaded -> load it"
|
|
#logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} -d ${key} 2>&1)"
|
|
$remove || logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} ${key} 2>&1)"
|
|
fi
|
|
done
|
|
fi
|
|
if ! $keyonly ; then
|
|
# load tokens
|
|
for pubkey in $(ls ${SSH_IDENTITIES_DIR}/${ssh_identity}/id_*|grep "pub$\|public$"|grep -v "cert.pub"); do
|
|
if $( ls ${pubkey%.pub} 1>/dev/null 2>&1);then
|
|
echo "pubkey with privkey: $pubkey"
|
|
else
|
|
echo "pubkey without privkey: $pubkey"
|
|
pubkeysonly+=($pubkey)
|
|
fi
|
|
if [ -e "${pubkey%.pub}-cert.pub" ]; then
|
|
#logwarn "${pubkey%.pub}-cert.pub: $(date +%s -d $(ssh-keygen -L -f "${pubkey%.pub}-cert.pub"|awk '$1 == "Valid:"{print $5}'))"
|
|
#logwarn "now: $(date +%s -d NOW)"
|
|
cert_exp_date=$(ssh-keygen -L -f "${pubkey%.pub}-cert.pub"|awk '$1 == "Valid:"{print $5}')
|
|
#[ $(date +%s -d $(ssh-keygen -L -f "${pubkey%.pub}-cert.pub"|awk '$1 == "Valid:"{print $5}')) -gt $(date +%s -d NOW) ] \
|
|
[ $(date +%s -d $cert_exp_date) -gt $(date +%s -d NOW) ] \
|
|
|| logwarn "CERTIFICATE IS NOT VALID ANYMORE: ${pubkey%.pub}-cert.pub"
|
|
#[ $(date +%s -d $(ssh-keygen -L -f "${pubkey%.pub}-cert.pub"|awk '$1 == "Valid:"{print $5}')) -lt $(date +%s -d "$SSH_CERT_VALIDITY_WARN_SEC") ] \
|
|
[ $(date +%s -d $cert_exp_date) -lt $(date +%s -d "$SSH_CERT_VALIDITY_WARN_SEC") ] \
|
|
&& logwarn "CERTIFICATE expires in $(echo "scale=0; ( `date -d $cert_exp_date +%s` - `date -d now +%s`) / (24*3600)" | bc -l) days: ${pubkey%.pub}-cert.pub"
|
|
fi
|
|
done
|
|
loginfo "pubkeysonly: ${pubkeysonly[@]} (count: ${#pubkeysonly[*]})"
|
|
|
|
|
|
for key in $(ls ${SSH_IDENTITIES_DIR}/${ssh_identity}/*|grep "\.so$"); do
|
|
logdebug "P11M: ${P11M:-not set} - key: $key"
|
|
#[ -e "${P11M-x}" ] || [ "$(readlink - f $key)" == "$P11M" ] || key="$P11M"
|
|
[ "$(readlink - f $key)" == "$P11M" ] || key="$P11M"
|
|
logdebug "P11M: ${P11M:-not set} - key: $key"
|
|
echo "P11M: ${P11M:-not set} - key: $key"
|
|
|
|
tokenfingerprint="$(ssh-keygen -l -D $key|tr -s ' '|awk '{print $2}')"
|
|
|
|
if [[ ${fingerprints[*]} =~ "$tokenfingerprint" ]]; then
|
|
logdebug "token: $key ($tokenfingerprint) is loaded"
|
|
check-pubkeysonly
|
|
if $readd || $remove ; then
|
|
$readd && logdebug "re-add token $key"
|
|
$remove && logdebug "remove token $key"
|
|
echo agentfile1 $agentfile \$SSH_ADD_OPTIONS $key >&2
|
|
logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} -e "${key}" 2>&1)"
|
|
ssh-runinagent $agentfile echo $SSH_AUTH_SOCK >&2
|
|
$remove || logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} -s "${key}" 2>&1)"
|
|
fi
|
|
else
|
|
logdebug "token: $key is not loaded -> load it"
|
|
logdebug "$(ssh-runinagent $agentfile ssh-add -v ${SSH_ADD_OPTIONS} -e ${key} 2>&1)"
|
|
$remove || logdebug "$(ssh-runinagent $agentfile ssh-add ${SSH_ADD_OPTIONS} -s ${key} 2>&1)"
|
|
fi
|
|
done
|
|
fi
|
|
loginfo "currently loaded keys after action: $(ssh-runinagent $agentfile ssh-add -l|wc -l)"
|
|
logdebug "$(ssh-runinagent $agentfile ssh-add -l)"
|
|
else
|
|
logwarn "ssh-identity $ssh_identity is not configured. Please create $identitydir and add keys"
|
|
fi
|
|
fi
|
|
EXIT
|
|
}
|
|
|
|
function check-pubkeysonly () {
|
|
if [ ${#pubkeysonly[*]} -gt 0 ] ; then
|
|
for p in ${pubkeysonly[@]}; do
|
|
ssh-runinagent $agentfile ssh-add -T ${p} 2>&1 || { $remove || readd=true; break; }
|
|
done
|
|
else
|
|
logwarn "obviously there is no pubkey for the token in ${SSH_IDENTITIES_DIR}/${ssh_identity}/"
|
|
logwarn "you can add the pubkey with"
|
|
logwarn " ssh-add -L > ${SSH_IDENTITIES_DIR}/${ssh_identity}/id_etoken.pub"
|
|
logwarn "make sure, only the token is loaded into ssh-agent with"
|
|
logwarn " ssh-add -l"
|
|
logwarn "only one line should be the output"
|
|
fi
|
|
logdebug "readd: $readd"
|
|
}
|
|
|
|
ssh-runinagent () {
|
|
|
|
ENTRY
|
|
|
|
local agentfile
|
|
local command
|
|
local agentfile=${1}
|
|
shift
|
|
local sshcommand=${@}
|
|
|
|
logtrace "run command »$sshcommand« in agent $agentfile"
|
|
if [ -e "$agentfile" ]; then
|
|
/bin/sh -c "unset SSH_AUTH_SOCK SSH_AGENT_PID; . $agentfile >/dev/null 2>/dev/null; $sshcommand"
|
|
ret=$?
|
|
else
|
|
logwarn "agentfile not existent"
|
|
ret=99
|
|
fi
|
|
|
|
EXIT
|
|
return $ret
|
|
|
|
}
|
|
|
|
if [[ $SSH_TTY || $X2GO_SESSION ]] ; then
|
|
logdebug "run with forwarded ssh-agent"
|
|
check_token
|
|
res=1
|
|
else
|
|
logdebug "run with local ssh-agent"
|
|
agent-start-or-restart $ssh_identity
|
|
! $createonly && agent-load-identity-keys $ssh_identity
|
|
res=0
|
|
fi
|
|
SCRIPTEXIT
|
|
exit $res
|