summaryrefslogtreecommitdiff
path: root/debian/patches/10-reimplement-known-hosts-file-parsing.patch
blob: f7db7ee7d7dc25dbe2f021d288b7b5f054300af9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
commit 71ac42b98c0eba39819fb8478d6443032c6ef6f1
Author: Ville Skyttä <ville.skytta@iki.fi>
Date:   Mon Mar 19 18:58:09 2018 +0200

    _known_hosts_real: Reimplement known hosts file parsing in pure bash

diff --git a/bash_completion b/bash_completion
index ca84b01d..98d277bd 100644
--- a/bash_completion
+++ b/bash_completion
@@ -1482,9 +1482,9 @@ _included_ssh_config_files()
 # Return: Completions, starting with CWORD, are added to COMPREPLY[]
 _known_hosts_real()
 {
-    local configfile flag prefix
-    local cur curd awkcur user suffix aliases i host ipv4 ipv6
-    local -a kh khd config
+    local configfile flag prefix OIFS=$IFS
+    local cur user suffix aliases i host ipv4 ipv6
+    local -a kh tmpkh khd config
 
     # TODO remove trailing %foo from entries
 
@@ -1523,8 +1523,7 @@ _known_hosts_real()
 
     # Known hosts files from configs
     if [[ ${#config[@]} -gt 0 ]]; then
-        local OIFS=$IFS IFS=$'\n' j
-        local -a tmpkh
+        local IFS=$'\n' j
         # expand paths (if present) to global and user known hosts files
         # TODO(?): try to make known hosts files with more than one consecutive
         #          spaces in their name work (watch out for ~ expansion
@@ -1561,35 +1560,31 @@ _known_hosts_real()
 
     # If we have known_hosts files to use
     if [[ ${#kh[@]} -gt 0 || ${#khd[@]} -gt 0 ]]; then
-        # Escape slashes and dots in paths for awk
-        awkcur=${cur//\//\\\/}
-        awkcur=${awkcur//\./\\\.}
-        curd=$awkcur
-
-        if [[ "$awkcur" == [0-9]*[.:]* ]]; then
-            # Digits followed by a dot or a colon - just search for that
-            awkcur="^$awkcur[.:]*"
-        elif [[ "$awkcur" == [0-9]* ]]; then
-            # Digits followed by no dot or colon - search for digits followed
-            # by a dot or a colon
-            awkcur="^$awkcur.*[.:]"
-        elif [[ -z $awkcur ]]; then
-            # A blank - search for a dot, a colon, or an alpha character
-            awkcur="[a-z.:]"
-        else
-            awkcur="^$awkcur"
-        fi
-
         if [[ ${#kh[@]} -gt 0 ]]; then
-            # FS needs to look for a comma separated list
-            COMPREPLY+=( $( awk 'BEGIN {FS=","}
-            /^\s*[^|\#]/ {
-            sub("^@[^ ]+ +", ""); \
-            sub(" .*$", ""); \
-            for (i=1; i<=NF; ++i) { \
-            sub("^\\[", "", $i); sub("\\](:[0-9]+)?$", "", $i); \
-            if ($i !~ /[*?]/ && $i ~ /'"$awkcur"'/) {print $i} \
-            }}' "${kh[@]}" 2>/dev/null ) )
+            # https://man.openbsd.org/sshd.8#SSH_KNOWN_HOSTS_FILE_FORMAT
+            for i in "${kh[@]}"; do
+                while read -ra tmpkh; do
+                    set -- "${tmpkh[@]}"
+                    # Skip entries starting with | (hashed) and # (comment)
+                    [[ $1 == [\|\#]* ]] && continue
+                    # Ignore leading @foo (markers)
+                    [[ $1 == @* ]] && shift
+                    # Split entry on commas
+                    local IFS=,
+                    for host in $1; do
+                        # Skip hosts containing wildcards
+                        [[ $host == *[*?]* ]] && continue
+                        # Remove leading [
+                        host="${host#[}"
+                        # Remove trailing ] + optional :port
+                        host="${host%]?(:+([0-9]))}"
+                        # Add host to candidates
+                        COMPREPLY+=( $host )
+                    done
+                    IFS=$OIFS
+                done < "$i"
+            done
+            COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) )
         fi
         if [[ ${#khd[@]} -gt 0 ]]; then
             # Needs to look for files called
@@ -1597,7 +1592,7 @@ _known_hosts_real()
             # dont fork any processes, because in a cluster environment,
             # there can be hundreds of hostkeys
             for i in "${khd[@]}" ; do
-                if [[ "$i" == *key_22_$curd*.pub && -r "$i" ]]; then
+                if [[ "$i" == *key_22_$cur*.pub && -r "$i" ]]; then
                     host=${i/#*key_22_/}
                     host=${host/%.pub/}
                     COMPREPLY+=( $host )