Skip to content

Commit 4ac86e8

Browse files
committed
fix(ssh): resolve relative ssh_config Include correctly
As per ssh_config man, "Files without absolute paths are assumed to be in ~/.ssh if included in a user configuration file or /etc/ssh if included from the system configuration file." So relative include base stays the same throughout recursion, even if the system-wide config is included from user's config. This commit also optimizes traversing ssh config includes. Previously each config file was read with separate `sed` command to extract `Include` directives. This can get quite slow if there are a lot of included files. Instead of reading each individual file, we can put all the files at a current recursion level into a single sed invocation and extract all the directives in one go.
1 parent a17197f commit 4ac86e8

File tree

1 file changed

+36
-25
lines changed

1 file changed

+36
-25
lines changed

bash_completion

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,33 +2111,44 @@ _included_ssh_config_files()
21112111
local configfile i files f
21122112
configfile=$1
21132113

2114+
# From man ssh_config:
2115+
# "Files without absolute paths are assumed to be in ~/.ssh if included
2116+
# in a user configuration file or /etc/ssh if included from the system
2117+
# configuration file."
2118+
# This behavior is not affected by the the including file location -
2119+
# if the system configuration file is included from the user's config,
2120+
# relative includes are still resolved in the user's ssh config directory.
2121+
local relative_include_base
2122+
if [[ $configfile == /etc/ssh* ]]; then
2123+
relative_include_base="/etc/ssh"
2124+
else
2125+
relative_include_base="$HOME/.ssh"
2126+
fi
2127+
2128+
local depth=1
21142129
local -a included
2115-
_comp_split included "$(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${configfile}")" || return
2116-
2117-
for i in "${included[@]}"; do
2118-
# Check the origin of $configfile to complete relative included paths on included
2119-
# files according to ssh_config(5):
2120-
# "[...] Files without absolute paths are assumed to be in ~/.ssh if included in a user
2121-
# configuration file or /etc/ssh if included from the system configuration file.[...]"
2122-
if ! [[ $i =~ ^\~.*|^\/.* ]]; then
2123-
if [[ $configfile =~ ^\/etc\/ssh.* ]]; then
2124-
i="/etc/ssh/$i"
2125-
else
2126-
i="$HOME/.ssh/$i"
2130+
local -a include_files
2131+
included=("$configfile")
2132+
2133+
while ((${#included[@]} > 0 && depth++ < 16)); do
2134+
_comp_split include_files "$(command sed -ne 's/^[[:blank:]]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][[:blank:]]\(.*\)$/\1/p' "${included[@]}")" || return
2135+
included=()
2136+
for i in "${include_files[@]}"; do
2137+
if [[ $i != [~/]* ]]; then
2138+
i="${relative_include_base}/${i}"
21272139
fi
2128-
fi
2129-
__expand_tilde_by_ref i
2130-
# In case the expanded variable contains multiple paths
2131-
_comp_expand_glob files '$i'
2132-
if ((${#files[@]})); then
2133-
for f in "${files[@]}"; do
2134-
if [[ -r $f && ! -d $f ]]; then
2135-
config+=("$f")
2136-
# The Included file is processed to look for Included files in itself
2137-
_included_ssh_config_files "$f"
2138-
fi
2139-
done
2140-
fi
2140+
__expand_tilde_by_ref i
2141+
# In case the expanded variable contains multiple paths
2142+
_comp_expand_glob files '$i'
2143+
if ((${#files[@]})); then
2144+
for f in "${files[@]}"; do
2145+
if [[ -r $f && ! -d $f ]]; then
2146+
config+=("$f")
2147+
included+=("$f")
2148+
fi
2149+
done
2150+
fi
2151+
done
21412152
done
21422153
} # _included_ssh_config_files()
21432154

0 commit comments

Comments
 (0)