mirror of
https://github.com/Gator96100/ProxSpace.git
synced 2025-01-09 20:33:34 -08:00
564 lines
16 KiB
Bash
564 lines
16 KiB
Bash
# ssh(1) completion -*- shell-script -*-
|
|
|
|
_ssh_queries()
|
|
{
|
|
COMPREPLY+=($(compgen -W \
|
|
"cipher cipher-auth help mac kex key key-cert key-plain key-sig
|
|
protocol-version compression sig
|
|
ciphers macs kexalgorithms pubkeyacceptedkeytypes
|
|
hostkeyalgorithms hostbasedkeytypes hostbasedacceptedkeytypes" \
|
|
-- "${cur,,}"))
|
|
}
|
|
|
|
_ssh_query()
|
|
{
|
|
${1:-ssh} -Q $2 2>/dev/null
|
|
}
|
|
|
|
_ssh_ciphers()
|
|
{
|
|
local ciphers='$(_ssh_query "$1" cipher)'
|
|
[[ $ciphers ]] || ciphers="3des-cbc aes128-cbc aes192-cbc aes256-cbc
|
|
aes128-ctr aes192-ctr aes256-ctr arcfour128 arcfour256 arcfour
|
|
blowfish-cbc cast128-cbc"
|
|
COMPREPLY+=($(compgen -W "$ciphers" -- "$cur"))
|
|
}
|
|
|
|
_ssh_macs()
|
|
{
|
|
local macs='$(_ssh_query "$1" mac)'
|
|
[[ $macs ]] || macs="hmac-md5 hmac-sha1 umac-64@openssh.com hmac-ripemd160
|
|
hmac-sha1-96 hmac-md5-96"
|
|
COMPREPLY+=($(compgen -W "$macs" -- "$cur"))
|
|
}
|
|
|
|
_ssh_options()
|
|
{
|
|
local opts=(
|
|
AddKeysToAgent AddressFamily BatchMode BindAddress CanonicalDomains
|
|
CanonicalizeFallbackLocal CanonicalizeHostname CanonicalizeMaxDots
|
|
CanonicalizePermittedCNAMEs CASignatureAlgorithms CertificateFile
|
|
ChallengeResponseAuthentication CheckHostIP Ciphers ClearAllForwardings
|
|
Compression ConnectionAttempts ConnectTimeout ControlMaster ControlPath
|
|
ControlPersist DynamicForward EnableSSHKeysign EscapeChar
|
|
ExitOnForwardFailure FingerprintHash ForwardAgent ForwardX11
|
|
ForwardX11Timeout ForwardX11Trusted GatewayPorts GlobalKnownHostsFile
|
|
GSSAPIAuthentication GSSAPIClientIdentity GSSAPIDelegateCredentials
|
|
GSSAPIKeyExchange GSSAPIRenewalForcesRekey GSSAPIServerIdentity
|
|
GSSAPITrustDns HashKnownHosts Host HostbasedAuthentication
|
|
HostbasedKeyTypes HostKeyAlgorithms HostKeyAlias HostName
|
|
IdentitiesOnly IdentityAgent IdentityFile IgnoreUnknown Include IPQoS
|
|
KbdInteractiveAuthentication KbdInteractiveDevices KexAlgorithms
|
|
LocalCommand LocalForward LogLevel MACs
|
|
NoHostAuthenticationForLocalhost NumberOfPasswordPrompts
|
|
PasswordAuthentication PermitLocalCommand PKCS11Provider Port
|
|
PreferredAuthentications ProxyCommand ProxyJump ProxyUseFdpass
|
|
PubkeyAcceptedKeyTypes PubkeyAuthentication RekeyLimit RemoteCommand
|
|
RemoteForward RequestTTY RevokedHostKeys SendEnv ServerAliveCountMax
|
|
ServerAliveInterval SmartcardDevice StreamLocalBindMask
|
|
StreamLocalBindUnlink StrictHostKeyChecking SyslogFacility TCPKeepAlive
|
|
Tunnel TunnelDevice UpdateHostKeys UsePrivilegedPort User
|
|
UserKnownHostsFile VerifyHostKeyDNS VisualHostKey XAuthLocation)
|
|
local protocols=$(_ssh_query "$1" protocol-version)
|
|
if [[ -z $protocols || $protocols == *1* ]]; then
|
|
opts+=(Cipher CompressionLevel Protocol RhostsRSAAuthentication
|
|
RSAAuthentication)
|
|
fi
|
|
|
|
compopt -o nospace
|
|
local IFS=$' \t\n' reset=$(shopt -p nocasematch)
|
|
shopt -s nocasematch
|
|
local option
|
|
COMPREPLY=($(for option in "${opts[@]}"; do
|
|
[[ $option == "$cur"* ]] && printf '%s=\n' "$option"
|
|
done))
|
|
$reset
|
|
}
|
|
|
|
# Complete a ssh suboption (like ForwardAgent=y<tab>)
|
|
# Two parameters: the string to complete including the equal sign, and
|
|
# the ssh executable to invoke (optional).
|
|
# Not all suboptions are completed.
|
|
# Doesn't handle comma-separated lists.
|
|
_ssh_suboption()
|
|
{
|
|
# Split into subopt and subval
|
|
local prev=${1%%=*} cur=${1#*=}
|
|
|
|
case ${prev,,} in
|
|
batchmode | canonicaldomains | canonicalizefallbacklocal | \
|
|
challengeresponseauthentication | checkhostip | \
|
|
clearallforwardings | controlpersist | compression | enablesshkeysign | \
|
|
exitonforwardfailure | forwardagent | forwardx11 | forwardx11trusted | \
|
|
gatewayports | gssapiauthentication | gssapikeyexchange | \
|
|
gssapidelegatecredentials | gssapirenewalforcesrekey | gssapitrustdns | \
|
|
hashknownhosts | hostbasedauthentication | identitiesonly | \
|
|
kbdinteractiveauthentication | kbdinteractivedevices | \
|
|
nohostauthenticationforlocalhost | passwordauthentication | permitlocalcommand | \
|
|
proxyusefdpass | pubkeyauthentication | rhostsrsaauthentication | \
|
|
rsaauthentication | streamlocalbindunlink | \
|
|
tcpkeepalive | useprivilegedport | visualhostkey)
|
|
COMPREPLY=($(compgen -W 'yes no' -- "$cur"))
|
|
;;
|
|
addkeystoagent)
|
|
COMPREPLY=($(compgen -W 'yes ask confirm no' -- "$cur"))
|
|
;;
|
|
addressfamily)
|
|
COMPREPLY=($(compgen -W 'any inet inet6' -- "$cur"))
|
|
;;
|
|
bindaddress)
|
|
_ip_addresses
|
|
;;
|
|
canonicalizehostname)
|
|
COMPREPLY=($(compgen -W 'yes no always' -- "$cur"))
|
|
;;
|
|
identityfile)
|
|
_ssh_identityfile
|
|
;;
|
|
*file | identityagent | include | controlpath | revokedhostkeys | xauthlocation)
|
|
_filedir
|
|
;;
|
|
casignaturealgorithms)
|
|
COMPREPLY=($(compgen -W '$(_ssh_query "$2" sig)' -- "$cur"))
|
|
;;
|
|
cipher)
|
|
COMPREPLY=($(compgen -W 'blowfish des 3des' -- "$cur"))
|
|
;;
|
|
ciphers)
|
|
_ssh_ciphers "$2"
|
|
;;
|
|
controlmaster)
|
|
COMPREPLY=($(compgen -W 'yes ask auto autoask no' -- "$cur"))
|
|
;;
|
|
compressionlevel)
|
|
COMPREPLY=($(compgen -W '{1..9}' -- "$cur"))
|
|
;;
|
|
fingerprinthash)
|
|
COMPREPLY=($(compgen -W 'md5 sha256' -- "$cur"))
|
|
;;
|
|
ipqos)
|
|
COMPREPLY=($(compgen -W 'af1{1..4} af2{2..3} af3{1..3} af4{1..3}
|
|
cs{0..7} ef lowdelay throughput reliability' -- "$cur"))
|
|
;;
|
|
hostbasedkeytypes | hostkeyalgorithms)
|
|
COMPREPLY=($(compgen -W '$(_ssh_query "$2" key)' -- "$cur"))
|
|
;;
|
|
kexalgorithms)
|
|
COMPREPLY=($(compgen -W '$(_ssh_query "$2" kex)' -- "$cur"))
|
|
;;
|
|
loglevel)
|
|
COMPREPLY=($(compgen -W 'QUIET FATAL ERROR INFO VERBOSE DEBUG{,1,2,3}' -- "$cur"))
|
|
;;
|
|
macs)
|
|
_ssh_macs "$2"
|
|
;;
|
|
pkcs11provider)
|
|
_filedir so
|
|
;;
|
|
preferredauthentications)
|
|
COMPREPLY=($(compgen -W 'gssapi-with-mic host-based publickey
|
|
keyboard-interactive password' -- "$cur"))
|
|
;;
|
|
protocol)
|
|
local protocols=($(_ssh_query "$2" protocol-version))
|
|
[[ $protocols ]] || protocols=(1 2)
|
|
if ((${#protocols[@]} > 1)); then
|
|
COMPREPLY=($(compgen -W '${protocols[@]}' -- "$cur"))
|
|
fi
|
|
;;
|
|
proxyjump)
|
|
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
;;
|
|
proxycommand | remotecommand | localcommand)
|
|
COMPREPLY=($(compgen -c -- "$cur"))
|
|
;;
|
|
pubkeyacceptedkeytypes)
|
|
COMPREPLY=($(compgen -W '$(_ssh_query "$2" key)' -- "$cur"))
|
|
;;
|
|
requesttty)
|
|
COMPREPLY=($(compgen -W 'no yes force auto' -- "$cur"))
|
|
;;
|
|
stricthostkeychecking)
|
|
COMPREPLY=($(compgen -W 'accept-new ask no off' -- "$cur"))
|
|
;;
|
|
syslogfacility)
|
|
COMPREPLY=($(compgen -W 'DAEMON USER AUTH LOCAL{0..7}' -- "$cur"))
|
|
;;
|
|
tunnel)
|
|
COMPREPLY=($(compgen -W 'yes no point-to-point ethernet' \
|
|
-- "$cur"))
|
|
;;
|
|
updatehostkeys | verifyhostkeydns)
|
|
COMPREPLY=($(compgen -W 'yes no ask' -- "$cur"))
|
|
;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
# Try to complete -o SubOptions=
|
|
#
|
|
# Returns 0 if the completion was handled or non-zero otherwise.
|
|
_ssh_suboption_check()
|
|
{
|
|
# Get prev and cur words without splitting on =
|
|
local cureq=$(_get_cword :=) preveq=$(_get_pword :=)
|
|
if [[ $cureq == *=* && $preveq == -*o ]]; then
|
|
_ssh_suboption $cureq "$1"
|
|
return $?
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Search COMP_WORDS for '-F configfile' or '-Fconfigfile' argument
|
|
_ssh_configfile()
|
|
{
|
|
set -- "${words[@]}"
|
|
while (($# > 0)); do
|
|
if [[ $1 == -F* ]]; then
|
|
if ((${#1} > 2)); then
|
|
configfile="$(dequote "${1:2}")"
|
|
else
|
|
shift
|
|
[[ ${1-} ]] && configfile="$(dequote "$1")"
|
|
fi
|
|
break
|
|
fi
|
|
shift
|
|
done
|
|
}
|
|
|
|
# With $1 set, look for public key files, else private
|
|
# shellcheck disable=SC2120
|
|
_ssh_identityfile()
|
|
{
|
|
[[ -z $cur && -d ~/.ssh ]] && cur=~/.ssh/id
|
|
_filedir
|
|
if ((${#COMPREPLY[@]} > 0)); then
|
|
COMPREPLY=($(compgen -W '${COMPREPLY[@]}' \
|
|
-X "${1:+!}*.pub" -- "$cur"))
|
|
fi
|
|
}
|
|
|
|
_ssh()
|
|
{
|
|
local cur prev words cword
|
|
_init_completion -n : || return
|
|
|
|
local configfile
|
|
_ssh_configfile
|
|
|
|
_ssh_suboption_check "$1" && return
|
|
|
|
local ipvx
|
|
|
|
case $prev in
|
|
-*b)
|
|
_ip_addresses
|
|
return
|
|
;;
|
|
-*c)
|
|
_ssh_ciphers "$1"
|
|
return
|
|
;;
|
|
-*[DeLpRW])
|
|
return
|
|
;;
|
|
-*[EFS])
|
|
_filedir
|
|
return
|
|
;;
|
|
-*i)
|
|
_ssh_identityfile
|
|
return
|
|
;;
|
|
-*I)
|
|
_filedir so
|
|
return
|
|
;;
|
|
-*J)
|
|
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
return
|
|
;;
|
|
-*l)
|
|
COMPREPLY=($(compgen -u -- "$cur"))
|
|
return
|
|
;;
|
|
-*m)
|
|
_ssh_macs "$1"
|
|
return
|
|
;;
|
|
-*O)
|
|
COMPREPLY=($(compgen -W 'check forward cancel exit stop' -- "$cur"))
|
|
return
|
|
;;
|
|
-*o)
|
|
_ssh_options "$1"
|
|
return
|
|
;;
|
|
-*Q)
|
|
_ssh_queries "$1"
|
|
return
|
|
;;
|
|
-*w)
|
|
_available_interfaces
|
|
return
|
|
;;
|
|
-*4*)
|
|
ipvx=-4
|
|
;;
|
|
-*6*)
|
|
ipvx=-6
|
|
;;
|
|
esac
|
|
|
|
if [[ $cur == -F* ]]; then
|
|
cur=${cur#-F}
|
|
_filedir
|
|
# Prefix completions with '-F'
|
|
COMPREPLY=("${COMPREPLY[@]/#/-F}")
|
|
cur=-F$cur # Restore cur
|
|
elif [[ $cur == -* ]]; then
|
|
COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
|
|
else
|
|
_known_hosts_real ${ipvx-} -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
|
|
local args
|
|
_count_args
|
|
if ((args > 1)); then
|
|
compopt -o filenames
|
|
COMPREPLY+=($(compgen -c -- "$cur"))
|
|
fi
|
|
fi
|
|
} &&
|
|
shopt -u hostcomplete && complete -F _ssh ssh slogin autossh sidedoor
|
|
|
|
# sftp(1) completion
|
|
#
|
|
_sftp()
|
|
{
|
|
local cur prev words cword
|
|
_init_completion || return
|
|
|
|
local configfile
|
|
_ssh_configfile
|
|
|
|
_ssh_suboption_check && return
|
|
|
|
local ipvx
|
|
|
|
case $prev in
|
|
-*[BDlPRs])
|
|
return
|
|
;;
|
|
-*[bF])
|
|
_filedir
|
|
return
|
|
;;
|
|
-*i)
|
|
_ssh_identityfile
|
|
return
|
|
;;
|
|
-*c)
|
|
_ssh_ciphers
|
|
return
|
|
;;
|
|
-*J)
|
|
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
return
|
|
;;
|
|
-*o)
|
|
_ssh_options
|
|
return
|
|
;;
|
|
-*S)
|
|
compopt -o filenames
|
|
COMPREPLY=($(compgen -c -- "$cur"))
|
|
return
|
|
;;
|
|
-*4*)
|
|
ipvx=-4
|
|
;;
|
|
-*6*)
|
|
ipvx=-6
|
|
;;
|
|
esac
|
|
|
|
if [[ $cur == -F* ]]; then
|
|
cur=${cur#-F}
|
|
_filedir
|
|
# Prefix completions with '-F'
|
|
COMPREPLY=("${COMPREPLY[@]/#/-F}")
|
|
cur=-F$cur # Restore cur
|
|
elif [[ $cur == -* ]]; then
|
|
COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
|
|
else
|
|
_known_hosts_real ${ipvx-} -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
fi
|
|
} &&
|
|
shopt -u hostcomplete && complete -F _sftp sftp
|
|
|
|
# things we want to backslash escape in scp paths
|
|
# shellcheck disable=SC2089
|
|
_scp_path_esc='[][(){}<>"'"'"',:;^&!$=?`\\|[:space:]]'
|
|
|
|
# Complete remote files with ssh. If the first arg is -d, complete on dirs
|
|
# only. Returns paths escaped with three backslashes.
|
|
# shellcheck disable=SC2120
|
|
_scp_remote_files()
|
|
{
|
|
local IFS=$'\n'
|
|
|
|
# remove backslash escape from the first colon
|
|
cur=${cur/\\:/:}
|
|
|
|
local userhost=${cur%%?(\\):*}
|
|
local path=${cur#*:}
|
|
|
|
# unescape (3 backslashes to 1 for chars we escaped)
|
|
# shellcheck disable=SC2090
|
|
path=$(command sed -e 's/\\\\\\\('$_scp_path_esc'\)/\\\1/g' <<<"$path")
|
|
|
|
# default to home dir of specified user on remote host
|
|
if [[ -z $path ]]; then
|
|
path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
|
|
fi
|
|
|
|
local files
|
|
if [[ $1 == -d ]]; then
|
|
# escape problematic characters; remove non-dirs
|
|
# shellcheck disable=SC2090
|
|
files=$(ssh -o 'Batchmode yes' $userhost \
|
|
command ls -aF1dL "$path*" 2>/dev/null |
|
|
command sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e '/[^\/]$/d')
|
|
else
|
|
# escape problematic characters; remove executables, aliases, pipes
|
|
# and sockets; add space at end of file names
|
|
# shellcheck disable=SC2090
|
|
files=$(ssh -o 'Batchmode yes' $userhost \
|
|
command ls -aF1dL "$path*" 2>/dev/null |
|
|
command sed -e 's/'$_scp_path_esc'/\\\\\\&/g' -e 's/[*@|=]$//g' \
|
|
-e 's/[^\/]$/& /g')
|
|
fi
|
|
COMPREPLY+=($files)
|
|
}
|
|
|
|
# This approach is used instead of _filedir to get a space appended
|
|
# after local file/dir completions, and -o nospace retained for others.
|
|
# If first arg is -d, complete on directory names only. The next arg is
|
|
# an optional prefix to add to returned completions.
|
|
_scp_local_files()
|
|
{
|
|
local IFS=$'\n'
|
|
|
|
local dirsonly=false
|
|
if [[ ${1-} == -d ]]; then
|
|
dirsonly=true
|
|
shift
|
|
fi
|
|
|
|
if $dirsonly; then
|
|
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
|
|
command sed -e "s/$_scp_path_esc/\\\\&/g" -e '/[^\/]$/d' -e "s/^/${1-}/"))
|
|
else
|
|
COMPREPLY+=($(command ls -aF1dL $cur* 2>/dev/null |
|
|
command sed -e "s/$_scp_path_esc/\\\\&/g" -e 's/[*@|=]$//g' \
|
|
-e 's/[^\/]$/& /g' -e "s/^/${1-}/"))
|
|
fi
|
|
}
|
|
|
|
# scp(1) completion
|
|
#
|
|
_scp()
|
|
{
|
|
local cur prev words cword
|
|
_init_completion -n : || return
|
|
|
|
local configfile
|
|
_ssh_configfile
|
|
|
|
_ssh_suboption_check && {
|
|
COMPREPLY=("${COMPREPLY[@]/%/ }")
|
|
return
|
|
}
|
|
|
|
local ipvx
|
|
|
|
case $prev in
|
|
-*c)
|
|
_ssh_ciphers
|
|
COMPREPLY=("${COMPREPLY[@]/%/ }")
|
|
return
|
|
;;
|
|
-*F)
|
|
_filedir
|
|
compopt +o nospace
|
|
return
|
|
;;
|
|
-*i)
|
|
_ssh_identityfile
|
|
compopt +o nospace
|
|
return
|
|
;;
|
|
-*J)
|
|
_known_hosts_real -a ${configfile:+-F "$configfile"} -- "$cur"
|
|
return
|
|
;;
|
|
-*[lP])
|
|
return
|
|
;;
|
|
-*o)
|
|
_ssh_options
|
|
return
|
|
;;
|
|
-*S)
|
|
compopt +o nospace -o filenames
|
|
COMPREPLY=($(compgen -c -- "$cur"))
|
|
return
|
|
;;
|
|
-*4*)
|
|
ipvx=-4
|
|
;;
|
|
-*6*)
|
|
ipvx=-6
|
|
;;
|
|
esac
|
|
|
|
_expand || return
|
|
|
|
case $cur in
|
|
!(*:*)/* | [.~]*) ;; # looks like a path
|
|
*:*)
|
|
_scp_remote_files
|
|
return
|
|
;;
|
|
esac
|
|
|
|
local prefix
|
|
|
|
if [[ $cur == -F* ]]; then
|
|
cur=${cur#-F}
|
|
prefix=-F
|
|
else
|
|
case $cur in
|
|
-*)
|
|
COMPREPLY=($(compgen -W '$(_parse_usage "${words[0]}")' \
|
|
-- "$cur"))
|
|
COMPREPLY=("${COMPREPLY[@]/%/ }")
|
|
return
|
|
;;
|
|
*/* | [.~]*)
|
|
# not a known host, pass through
|
|
;;
|
|
*)
|
|
_known_hosts_real ${ipvx-} -c -a \
|
|
${configfile:+-F "$configfile"} -- "$cur"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
_scp_local_files "${prefix-}"
|
|
} &&
|
|
complete -F _scp -o nospace scp
|
|
|
|
# ex: filetype=sh
|