289 lines
10 KiB
Bash
289 lines
10 KiB
Bash
#!/bin/zsh
|
|
|
|
# _ssh_agent_plugin_debug function
|
|
function _ssh_agent_plugin_debug() {
|
|
local _ssh_agent_plugin_verbose
|
|
zstyle -b :xals:plugins:ssh-agent verbose _ssh_agent_plugin_verbose
|
|
|
|
if [[ "${_ssh_agent_plugin_verbose}" == "yes" ]]; then
|
|
echo $*
|
|
fi
|
|
}
|
|
|
|
# Function to clean global link
|
|
function _ssh_agent_plugin_clean_global_sock() {
|
|
# Clean link to obsolete auth socket.
|
|
if [ -L "${_ssh_agent_plugin_sock}" ]; then
|
|
_ssh_agent_plugin_debug "Found global link to socket, checking it."
|
|
|
|
if [ -S "${_ssh_agent_plugin_sock}" -a -w "${_ssh_agent_plugin_sock}" ]; then
|
|
_ssh_agent_plugin_debug "Global link relating to a valid socket, keeping it."
|
|
else
|
|
_ssh_agent_plugin_debug "Found a broken global link, removing it."
|
|
|
|
# Remove obsolete global link
|
|
unlink "${_ssh_agent_plugin_sock}"
|
|
fi
|
|
elif [ -e "${_ssh_agent_plugin_sock}" ]; then
|
|
# Note: here ${_ssh_agent_plugin_sock} may exist, but may be not a symlink, we remove it.
|
|
_ssh_agent_plugin_debug "Found garbage, cleaning up."
|
|
|
|
rm -f "${_ssh_agent_plugin_sock}"
|
|
fi
|
|
}
|
|
|
|
function _ssh_agent_plugin_clean_auth_sock() {
|
|
# Cleanup ${SSH_AUTH_SOCK} if not a valid socket.
|
|
if [ -S "${SSH_AUTH_SOCK}" -a -w "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Auth socket is valid."
|
|
else
|
|
if [ -e "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Found garbage, cleaning up."
|
|
|
|
rm -f "${SSH_AUTH_SOCK}"
|
|
fi
|
|
|
|
if [ -n "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Found an invalid \${SSH_AUTH_SOCK}, unsetting it."
|
|
|
|
unset SSH_AUTH_SOCK
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function _ssh_agent_plugin_launch_agent() {
|
|
if [ -S "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Found valid \${SSH_AUTH_SOCK}."
|
|
else
|
|
# We don't have an SSH auth socket, we try to create one.
|
|
if [ -x "$(which keychain)" ]; then
|
|
_ssh_agent_plugin_debug "Launching keychain."
|
|
|
|
# Launch keychain
|
|
_ssh_agent_plugin_run_keychain
|
|
elif [ -x "$(which ssh-agent)" ]; then
|
|
_ssh_agent_plugin_debug "Lauching classic SSH agent."
|
|
|
|
_ssh_agent_plugin_run_classic_agent
|
|
else
|
|
_ssh_agent_plugin_debug "No valid SSH agent manager found."
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function _ssh_agent_plugin_export_global_sock() {
|
|
# Export SSH authentication socket if socket is valid.
|
|
if [ -S "${_ssh_agent_plugin_sock}" -a -w "${_ssh_agent_plugin_sock}" ]; then
|
|
if [ "${_ssh_agent_plugin_sock}" != "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Exporting ${_ssh_agent_plugin_sock} as new \${SSH_AUTH_SOCK}."
|
|
|
|
export SSH_AUTH_SOCK="${_ssh_agent_plugin_sock}"
|
|
else
|
|
_ssh_agent_plugin_debug "\${_ssh_agent_plugin_sock} is already the same as \${SSH_AUTH_SOCK}."
|
|
fi
|
|
else
|
|
_ssh_agent_plugin_debug "${_ssh_agent_plugin_sock} is not a valid socket."
|
|
fi
|
|
}
|
|
|
|
function _ssh_agent_plugin_link_global_sock() {
|
|
# Link to existing socket, if we are not already linked to it
|
|
if [ -S "${SSH_AUTH_SOCK}" -a -w "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Found valid \${SSH_AUTH_SOCK}."
|
|
|
|
if [ "${SSH_AUTH_SOCK}" != "${_ssh_agent_plugin_sock}" ]; then
|
|
# Update link with new socket if needed
|
|
if [ -S "${SSH_AUTH_SOCK}" -a -w "${SSH_AUTH_SOCK}" ]; then
|
|
_ssh_agent_plugin_debug "Linking to new valid \${SSH_AUTH_SOCK}."
|
|
|
|
ln -sf "${SSH_AUTH_SOCK}" "${_ssh_agent_plugin_sock}"
|
|
else
|
|
_ssh_agent_plugin_debug "Don't have a valid \${SSH_AUTH_SOCK} to link to."
|
|
fi
|
|
else
|
|
_ssh_agent_plugin_debug "Already using linked socket."
|
|
fi
|
|
else
|
|
_ssh_agent_plugin_debug "Didn't find valid \${SSH_AUTH_SOCK} to link to."
|
|
fi
|
|
}
|
|
|
|
# launch SSH agent
|
|
function _ssh_agent_plugin_init() {
|
|
local -x _ssh_agent_plugin_sock
|
|
zstyle -s :xals:plugins:ssh-agent global_sock _ssh_agent_plugin_sock
|
|
|
|
local _ssh_agent_plugin_enable_root
|
|
zstyle -b :xals:plugins:ssh-agent enable_root _ssh_agent_plugin_enable_root
|
|
|
|
local -x _ssh_agent_plugin_directory="$HOME/.ssh"
|
|
|
|
if [ ! -d "${_ssh_agent_plugin_directory}" ]; then
|
|
_ssh_agent_plugin_debug "Creating ${_ssh_agent_plugin_directory} directory."
|
|
|
|
mkdir "${_ssh_agent_plugin_directory}"
|
|
chmod 700 "${_ssh_agent_plugin_directory}"
|
|
fi
|
|
|
|
# Reuse user authentication socket if I am root and using sudo.
|
|
if [ -z "${_ssh_agent_plugin_sock}" ]; then
|
|
if [ "${USER}" != "root" ]; then
|
|
_ssh_agent_plugin_sock="/tmp/ssh-agent-$USER"
|
|
elif [ "${_ssh_agent_plugin_enable_root}" == "yes" ]; then
|
|
if [ -n "${SUDO_USER}" ]; then
|
|
_ssh_agent_plugin_sock="/tmp/ssh-agent-$SUDO_USER"
|
|
else
|
|
_ssh_agent_plugin_sock="/tmp/ssh-agent-$USER"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
_ssh_agent_plugin_debug "Static socket will be: \"${_ssh_agent_plugin_sock}\"."
|
|
|
|
# We want to do socket linking only if it is necessary
|
|
if [ -n "${_ssh_agent_plugin_sock}" ]; then
|
|
_ssh_agent_plugin_debug "Global socket is defined"
|
|
|
|
# Clean global link.
|
|
_ssh_agent_plugin_clean_global_sock
|
|
|
|
# Clean auth sock.
|
|
_ssh_agent_plugin_clean_auth_sock
|
|
|
|
# First time export.
|
|
_ssh_agent_plugin_export_global_sock
|
|
|
|
# Launch agent if not valid SSH_AUTH_SOCK found.
|
|
_ssh_agent_plugin_launch_agent
|
|
|
|
# Link to SSH_AUTH_SOCK.
|
|
_ssh_agent_plugin_link_global_sock
|
|
|
|
# Second time export.
|
|
_ssh_agent_plugin_export_global_sock
|
|
|
|
# Add identities.
|
|
_ssh_agent_plugin_add_identities
|
|
fi
|
|
}
|
|
|
|
# Use keychain to launch SSH agent.
|
|
function _ssh_agent_plugin_run_keychain() {
|
|
if [ -x "$(which keychain)" ]; then
|
|
keychain --quiet --nogui --inherit any --agents ssh
|
|
|
|
[ -r $HOME/.keychain/$(hostname)-sh ] && source $HOME/.keychain/$(hostname)-sh
|
|
fi
|
|
}
|
|
|
|
# Launch classic SSH agent.
|
|
function _ssh_agent_plugin_run_classic_agent() {
|
|
# We launch the agent only if there is not auth socket.
|
|
if [ -S "${SSH_AUTH_SOCK}" -a -w "${SSH_AUTH_SOCK}" ]; then
|
|
# We should not be here, but just in case...
|
|
else
|
|
if [ -e "${SSH_AUTH_SOCK}" ]; then
|
|
# Should not happen... Just in case...
|
|
rm -f "${SSH_AUTH_SOCK}"
|
|
fi
|
|
|
|
if [ -x "$(which ssh-agent)" ]; then
|
|
local _ssh_agent_plugin_pidfile="${_ssh_agent_plugin_directory}/agent-pid"
|
|
|
|
# Cleanup old PID file
|
|
if [ -r "${_ssh_agent_plugin_pidfile}" ]; then
|
|
local _ssh_agent_plugin_pid=$(< "${_ssh_agent_plugin_pidfile}")
|
|
|
|
_ssh_agent_plugin_debug "Found a PID file with value ${_ssh_agent_plugin_pid}."
|
|
if [ ! -e "${_ssh_agent_plugin_pid}" ] ; then
|
|
_ssh_agent_plugin_debug "Removing remaining PID file."
|
|
|
|
rm -f "${_ssh_agent_plugin_pidfile}"
|
|
fi
|
|
fi
|
|
|
|
if [ -r "${_ssh_agent_plugin_pidfile}" ]; then
|
|
_ssh_agent_plugin_debug "Killing existing agent."
|
|
|
|
export SSH_AGENT_PID=$(< "${_ssh_agent_plugin_pidfile}")
|
|
eval $(ssh-agent -s -k) > /dev/null
|
|
rm -f "${_ssh_agent_plugin_pidfile}"
|
|
fi
|
|
|
|
_ssh_agent_plugin_debug "Launching SSH agent."
|
|
|
|
local _ssh_agent_plugin_lifetime
|
|
zstyle -s :xals:plugins:ssh-agent lifetime _ssh_agent_plugin_lifetime
|
|
|
|
eval $(ssh-agent -s ${_ssh_agent_plugin_lifetime:+-t} ${_ssh_agent_plugin_lifetime}) > /dev/null
|
|
echo $SSH_AGENT_PID > "${_ssh_agent_plugin_pidfile}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Add SSH key if not already added.
|
|
function _ssh_agent_plugin_add_identities() {
|
|
if [ -x "$(which ssh-add)" ]; then
|
|
# "ssh-add -l" return codes:
|
|
# 0: one or more keys were found.
|
|
# 1: no key was found.
|
|
# 2: agent could not be contacted.
|
|
|
|
local _ssh_agent_plugin_identities
|
|
zstyle -a :xals:plugins:ssh-agent identities _ssh_agent_plugin_identities
|
|
|
|
if [ "${#_ssh_agent_plugin_identities}" -eq 0 ]; then
|
|
_ssh_agent_plugin_identities=("id_rsa")
|
|
fi
|
|
|
|
ssh-add -l > /dev/null
|
|
|
|
if [ 2 -eq $? ] ; then
|
|
# Agent is not launched
|
|
_ssh_agent_plugin_debug "Agent is not launched. Probably no key available."
|
|
else
|
|
# Agent has identities added, check if the ones we want are present, add them if not.
|
|
local _ssh_agent_plugin_identity
|
|
|
|
for _ssh_agent_plugin_identity in ${_ssh_agent_plugin_identities}; do
|
|
local _ssh_agent_plugin_identity_absolute_path
|
|
_ssh_agent_plugin_identity_absolute_path=$(readlink -f "${_ssh_agent_plugin_directory}/${_ssh_agent_plugin_identity}")
|
|
|
|
if [ -r "${_ssh_agent_plugin_identity_absolute_path}" ]; then
|
|
ssh-add -l | awk '{print $3}' | while read _ssh_agent_plugin_added_identity; do
|
|
readlink -f "${_ssh_agent_plugin_added_identity}" | grep -q "${_ssh_agent_plugin_identity_absolute_path}"
|
|
done
|
|
|
|
if [ $? -ne 0 ]; then
|
|
_ssh_agent_plugin_debug "Adding ${_ssh_agent_plugin_identity} identity."
|
|
|
|
ssh-add "${_ssh_agent_plugin_identity_absolute_path}"
|
|
else
|
|
_ssh_agent_plugin_debug "${_ssh_agent_plugin_identity} identity already added."
|
|
fi
|
|
else
|
|
_ssh_agent_plugin_debug "${_ssh_agent_plugin_identity} identity does not exist."
|
|
fi
|
|
done
|
|
fi
|
|
fi
|
|
}
|
|
|
|
_ssh_agent_plugin_init
|
|
|
|
unfunction _ssh_agent_plugin_init
|
|
|
|
unfunction _ssh_agent_plugin_clean_global_sock
|
|
unfunction _ssh_agent_plugin_clean_auth_sock
|
|
unfunction _ssh_agent_plugin_export_global_sock
|
|
unfunction _ssh_agent_plugin_launch_agent
|
|
unfunction _ssh_agent_plugin_link_global_sock
|
|
|
|
unfunction _ssh_agent_plugin_run_keychain
|
|
unfunction _ssh_agent_plugin_run_classic_agent
|
|
|
|
unfunction _ssh_agent_plugin_add_identities
|
|
|
|
unfunction _ssh_agent_plugin_debug
|
|
|