summaryrefslogtreecommitdiffstats
path: root/completions/ssh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--completions/ssh563
-rw-r--r--completions/ssh-add35
-rw-r--r--completions/ssh-copy-id32
-rw-r--r--completions/ssh-keygen123
-rw-r--r--completions/sshfs23
-rw-r--r--completions/sshmitm17
-rw-r--r--completions/sshow26
7 files changed, 819 insertions, 0 deletions
diff --git a/completions/ssh b/completions/ssh
new file mode 100644
index 0000000..907c039
--- /dev/null
+++ b/completions/ssh
@@ -0,0 +1,563 @@
+# 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
diff --git a/completions/ssh-add b/completions/ssh-add
new file mode 100644
index 0000000..d8f7492
--- /dev/null
+++ b/completions/ssh-add
@@ -0,0 +1,35 @@
+# ssh-add(1) completion -*- shell-script -*-
+
+_ssh_add()
+{
+ local cur prev words cword
+ _init_completion || return
+
+ case $prev in
+ -*E)
+ COMPREPLY=($(compgen -W 'md5 sha256' -- "$cur"))
+ return
+ ;;
+ -*t)
+ return
+ ;;
+ -*T)
+ _filedir
+ return
+ ;;
+ -*[se])
+ _filedir so
+ return
+ ;;
+ esac
+
+ if [[ $cur == -* ]]; then
+ COMPREPLY=($(compgen -W '$(_parse_help "$1" "-\?")' -- "$cur"))
+ return
+ fi
+
+ _filedir
+} &&
+ complete -F _ssh_add ssh-add
+
+# ex: filetype=sh
diff --git a/completions/ssh-copy-id b/completions/ssh-copy-id
new file mode 100644
index 0000000..f628194
--- /dev/null
+++ b/completions/ssh-copy-id
@@ -0,0 +1,32 @@
+# ssh-copy-id(1) completion -*- shell-script -*-
+
+_ssh_copy_id()
+{
+ local cur prev words cword
+ _init_completion || return
+
+ _xfunc ssh _ssh_suboption_check "$1" && return
+
+ case $prev in
+ -i)
+ _xfunc ssh _ssh_identityfile pub
+ return
+ ;;
+ -p)
+ return
+ ;;
+ -o)
+ _xfunc ssh _ssh_options
+ return
+ ;;
+ esac
+
+ if [[ $cur == -* ]]; then
+ COMPREPLY=($(compgen -W '$(_parse_usage "$1" --help)' -- "$cur"))
+ else
+ _known_hosts_real -a -- "$cur"
+ fi
+} &&
+ complete -F _ssh_copy_id ssh-copy-id
+
+# ex: filetype=sh
diff --git a/completions/ssh-keygen b/completions/ssh-keygen
new file mode 100644
index 0000000..0e629a5
--- /dev/null
+++ b/completions/ssh-keygen
@@ -0,0 +1,123 @@
+# ssh-keygen(1) completion -*- shell-script -*-
+
+_ssh_keygen()
+{
+ local cur prev words cword
+ _init_completion -n := || return
+
+ case $prev in
+ -*[aCIJjMNPSVWz])
+ return
+ ;;
+ -*b)
+ local -a sizes
+ case "${words[*]}" in
+ *" -t dsa"?( *))
+ sizes=(1024)
+ ;;
+ *" -t ecdsa"?( *))
+ sizes=(256 384 521)
+ ;;
+ *" -t rsa"?( *))
+ sizes=(1024 2048 3072 4096)
+ ;;
+ esac
+ COMPREPLY=($(compgen -W '${sizes[@]}' -- "$cur"))
+ return
+ ;;
+ -*E)
+ COMPREPLY=($(compgen -W 'md5 sha256' -- "$cur"))
+ return
+ ;;
+ -*[FR])
+ # TODO: trim this down to actual entries in known hosts files
+ _known_hosts_real -- "$cur"
+ return
+ ;;
+ -*[Dw])
+ _filedir so
+ return
+ ;;
+ -*[fGKsT])
+ _filedir
+ return
+ ;;
+ -*m)
+ COMPREPLY=($(compgen -W 'PEM PKCS8 RFC4716' -- "$cur"))
+ return
+ ;;
+ -*n)
+ [[ ${words[*]} != *\ -*Y\ * ]] || return
+ local prefix=
+ [[ $cur == *,* ]] && prefix="${cur%,*},"
+ if [[ ${words[*]} == *\ -*h\ * ]]; then
+ _known_hosts_real -- "${cur##*,}"
+ else
+ COMPREPLY=($(compgen -u -- "${cur##*,}"))
+ fi
+ ((${#COMPREPLY[@]} == 1)) && COMPREPLY=(${COMPREPLY/#/$prefix})
+ return
+ ;;
+ -*O)
+ if [[ $cur != *=* ]]; then
+ COMPREPLY=($(compgen -W '
+ clear critical: extension: force-command=
+ no-agent-forwarding no-port-forwarding no-pty no-user-rc
+ no-x11-forwarding permit-agent-forwarding
+ permit-port-forwarding permit-pty permit-user-rc
+ permit-X11-forwarding no-touch-required source-address=
+
+ lines= start-line= checkpoint= memory= start= generator=
+
+ application challenge= device resident user
+ write-attestation-path
+ ' -- "$cur"))
+ [[ ${COMPREPLY-} == *[:=] ]] && compopt -o nospace
+ __ltrim_colon_completions "$cur"
+ else
+ case $cur in
+ force-command=*)
+ compopt -o filenames
+ COMPREPLY=($(compgen -c -- "${cur#*=}"))
+ ;;
+ checkpoint=* | challenge=*)
+ cur=${cur#*=}
+ _filedir
+ ;;
+ esac
+ fi
+ return
+ ;;
+ -*r)
+ [[ ${words[*]} != *\ -*Y\ * ]] || _filedir
+ return
+ ;;
+ -*t)
+ local protocols=$(_xfunc ssh _ssh_query "$1" protocol-version)
+ local types='dsa ecdsa ecdsa-sk ed25519 ed25519-sk rsa'
+ if [[ $protocols == *1* ]]; then
+ types+=' rsa1'
+ fi
+ COMPREPLY=($(compgen -W "$types" -- "$cur"))
+ return
+ ;;
+ -*Y)
+ COMPREPLY=($(compgen -W 'find-principals check-novalidate sign
+ verify' -- "$cur"))
+ return
+ ;;
+ esac
+
+ if [[ $cur == -* ]]; then
+ local opts=$(_parse_usage "$1" "-?")
+ [[ -z $opts ]] && opts=$(_parse_help "$1" "-?") # OpenSSH < 7
+ COMPREPLY=($(compgen -W "$opts" -- "$cur"))
+ fi
+
+ if [[ ${words[*]} == *\ -*s\ * ]]; then
+ _filedir pub
+ fi
+} &&
+ complete -F _ssh_keygen ssh-keygen
+
+# ex: filetype=sh
diff --git a/completions/sshfs b/completions/sshfs
new file mode 100644
index 0000000..223d029
--- /dev/null
+++ b/completions/sshfs
@@ -0,0 +1,23 @@
+# sshfs(1) completion -*- shell-script -*-
+
+_sshfs()
+{
+ local cur prev words cword
+ _init_completion -n : || return
+
+ _expand || return
+
+ if [[ $cur == *:* ]]; then
+ _xfunc ssh _scp_remote_files -d
+ # unlike scp and rsync, sshfs works with 1 backslash instead of 3
+ COMPREPLY=("${COMPREPLY[@]//\\\\\\/\\}")
+ return
+ fi
+
+ [[ $cur == @(*/|[.~])* ]] || _known_hosts_real -c -a -- "$cur"
+
+ _xfunc ssh _scp_local_files -d
+} &&
+ complete -F _sshfs -o nospace sshfs
+
+# ex: filetype=sh
diff --git a/completions/sshmitm b/completions/sshmitm
new file mode 100644
index 0000000..ee893e5
--- /dev/null
+++ b/completions/sshmitm
@@ -0,0 +1,17 @@
+# sshmitm completion -*- shell-script -*-
+
+_sshmitm()
+{
+ local cur prev words cword
+ _init_completion || return
+
+ if [[ $cur == -* ]]; then
+ COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
+ else
+ _known_hosts_real -- "$cur"
+ fi
+
+} &&
+ complete -F _sshmitm sshmitm
+
+# ex: filetype=sh
diff --git a/completions/sshow b/completions/sshow
new file mode 100644
index 0000000..917444e
--- /dev/null
+++ b/completions/sshow
@@ -0,0 +1,26 @@
+# sshow completion -*- shell-script -*-
+
+_sshow()
+{
+ local cur prev words cword
+ _init_completion || return
+
+ case $prev in
+ -*i)
+ _available_interfaces -a
+ return
+ ;;
+ -*p)
+ _filedir pcap
+ return
+ ;;
+ esac
+
+ if [[ $cur == -* ]]; then
+ COMPREPLY=($(compgen -W '$(_parse_usage "$1")' -- "$cur"))
+ fi
+
+} &&
+ complete -F _sshow sshow
+
+# ex: filetype=sh