Skip to content

Commit 0263f35

Browse files
authored
Sshconfig missing bugfix - addresses issue #1105 (#1109)
* update log output to indicate intentions moving forward * if we have failed to read the ssh_config file, ignore it entirely * add defensive code path that dies if for some reason even this fails * added this to prevent double warnings in case of missing file * allow for sshcfg to be nil, which implies no ssh_config found * update keypath configuration to allow for nil sshcfg * update HostName configuration to allow for nil sshcfg * update StrictHostKeyChecking to allow for nil sshcfg * update UserKnownHostsFile to allow for nil sshcfg * update HostKeyAlgorithms to allow for nil sshcfg * remove ProxyCommand from main codepath - while still warning of use * update ProxyJump config to allow for nil sshcfg * update user config to allow for nil sshcfg while also simplifying the code would previously get the current user (current execution's context) whereas the cfg.User value already takes the ConnectionURI's set username which should be sufficient as a default value check. * fix spelling mistake * why commit once when twice would suffice
1 parent b56a61c commit 0263f35

File tree

1 file changed

+62
-50
lines changed

1 file changed

+62
-50
lines changed

libvirt/uri/ssh.go

Lines changed: 62 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"log"
66
"net"
77
"os"
8-
"os/user"
98
"path/filepath"
109
"strings"
1110

@@ -39,19 +38,22 @@ func (u *ConnectionURI) parseAuthMethods(target string, sshcfg *ssh_config.Confi
3938
// 2. load override as specified in ssh config
4039
// 3. load default ssh keyfile path
4140
sshKeyPaths := []string{}
41+
4242
sshKeyPath := q.Get("keyfile")
4343
if sshKeyPath != "" {
4444
sshKeyPaths = append(sshKeyPaths, sshKeyPath)
4545
}
4646

47-
keyPaths, err := sshcfg.GetAll(target, "IdentityFile")
48-
if err != nil {
49-
log.Printf("[WARN] unable to get IdentityFile values - ignoring")
50-
} else {
51-
sshKeyPaths = append(sshKeyPaths, keyPaths...)
47+
if sshcfg != nil {
48+
keyPaths, err := sshcfg.GetAll(target, "IdentityFile")
49+
if err != nil {
50+
log.Printf("[WARN] unable to get IdentityFile values - ignoring")
51+
} else {
52+
sshKeyPaths = append(sshKeyPaths, keyPaths...)
53+
}
5254
}
5355

54-
if len(keyPaths) == 0 {
56+
if len(sshKeyPaths) == 0 {
5557
log.Printf("[DEBUG] found no ssh keys, using default keypath")
5658
sshKeyPaths = []string{defaultSSHKeyPath}
5759
}
@@ -116,14 +118,17 @@ func (u *ConnectionURI) parseAuthMethods(target string, sshcfg *ssh_config.Confi
116118
// construct the whole ssh connection, which can consist of multiple hops if using proxy jumps,
117119
// the ssh configuration file is loaded once and passed along to each host connection.
118120
func (u *ConnectionURI) dialSSH() (net.Conn, error) {
121+
var sshcfg* ssh_config.Config = nil
122+
119123
sshConfigFile, err := os.Open(os.ExpandEnv(defaultSSHConfigFile))
120124
if err != nil {
121125
log.Printf("[WARN] Failed to open ssh config file: %v", err)
122-
}
126+
} else {
127+
sshcfg, err = ssh_config.Decode(sshConfigFile)
128+
if err != nil {
129+
log.Printf("[WARN] Failed to parse ssh config file: '%v' - sshconfig will be ignored.", err)
130+
}
123131

124-
sshcfg, err := ssh_config.Decode(sshConfigFile)
125-
if err != nil {
126-
log.Printf("[WARN] Failed to parse ssh config file: %v", err)
127132
}
128133

129134
// configuration loaded, build tunnel
@@ -164,11 +169,11 @@ func (u *ConnectionURI) dialHost(target string, sshcfg *ssh_config.Config, depth
164169
log.Printf("[DEBUG] ssh Port is overridden to: '%s'", port)
165170
}
166171

167-
hostName, err := sshcfg.Get(target, "HostName")
168-
if err == nil {
169-
if hostName == "" {
170-
hostName = target
171-
} else {
172+
hostName := target
173+
if sshcfg != nil {
174+
host, err := sshcfg.Get(target, "HostName")
175+
if err == nil && host != "" {
176+
hostName = host
172177
log.Printf("[DEBUG] HostName is overridden to: '%s'", hostName)
173178
}
174179
}
@@ -182,18 +187,22 @@ func (u *ConnectionURI) dialHost(target string, sshcfg *ssh_config.Config, depth
182187
if knownHostsVerify == "ignore" {
183188
skipVerify = true
184189
} else {
185-
strictCheck, err := sshcfg.Get(target, "StrictHostKeyChecking")
186-
if err != nil && strictCheck == "yes" {
187-
skipVerify = false
190+
if sshcfg != nil {
191+
strictCheck, err := sshcfg.Get(target, "StrictHostKeyChecking")
192+
if err != nil && strictCheck == "yes" {
193+
skipVerify = false
194+
}
188195
}
189196
}
190197

191198
if knownHostsPath == "" {
192-
knownHosts, err := sshcfg.Get(target, "UserKnownHostsFile")
193-
if err == nil && knownHosts != "" {
194-
knownHostsPath = knownHosts
195-
} else {
196-
knownHostsPath = defaultSSHKnownHostsPath
199+
knownHostsPath = defaultSSHKnownHostsPath
200+
201+
if sshcfg != nil {
202+
knownHosts, err := sshcfg.Get(target, "UserKnownHostsFile")
203+
if err == nil && knownHosts != "" {
204+
knownHostsPath = knownHosts
205+
}
197206
}
198207
}
199208

@@ -226,10 +235,12 @@ func (u *ConnectionURI) dialHost(target string, sshcfg *ssh_config.Config, depth
226235
return err
227236
}
228237

229-
keyAlgs, err := sshcfg.Get(target, "HostKeyAlgorithms")
230-
if err == nil && keyAlgs != "" {
231-
log.Printf("Got host key algorithms '%s'", keyAlgs)
232-
hostKeyAlgorithms = strings.Split(keyAlgs, ",")
238+
if sshcfg != nil {
239+
keyAlgs, err := sshcfg.Get(target, "HostKeyAlgorithms")
240+
if err == nil && keyAlgs != "" {
241+
log.Printf("[DEBUG] HostKeyAlgorithms is overridden to '%s'", keyAlgs)
242+
hostKeyAlgorithms = strings.Split(keyAlgs, ",")
243+
}
233244
}
234245

235246
}
@@ -240,46 +251,47 @@ func (u *ConnectionURI) dialHost(target string, sshcfg *ssh_config.Config, depth
240251
HostKeyAlgorithms: hostKeyAlgorithms,
241252
Timeout: dialTimeout,
242253
}
254+
var bastion *ssh.Client = nil
255+
var bastion_proxy string = ""
243256

244-
proxy, err := sshcfg.Get(target, "ProxyCommand")
245-
if err == nil && proxy != "" {
246-
log.Printf("[WARNING] unsupported ssh ProxyCommand '%v'", proxy)
257+
if sshcfg != nil {
258+
command, err := sshcfg.Get(target, "ProxyCommand")
259+
if err == nil && command != "" {
260+
log.Printf("[WARNING] unsupported ssh ProxyCommand '%v' - ignoring", command)
261+
}
247262
}
248263

249-
proxy, err = sshcfg.Get(target, "ProxyJump")
250-
var bastion *ssh.Client
251-
if err == nil && proxy != "" {
252-
log.Printf("[DEBUG] found ProxyJump '%v'", proxy)
253-
254-
// this is a proxy jump: we recurse into that proxy
255-
bastion, err = u.dialHost(proxy, sshcfg, depth+1)
256-
if err != nil {
257-
return nil, fmt.Errorf("failed to connect to bastion host '%v': %w", proxy, err)
264+
if sshcfg != nil {
265+
proxy, err := sshcfg.Get(target, "ProxyJump")
266+
if err == nil && proxy != "" {
267+
log.Printf("[DEBUG] found ProxyJump '%v'", proxy)
268+
// this is a proxy jump: we recurse into that proxy
269+
bastion, err = u.dialHost(proxy, sshcfg, depth+1)
270+
bastion_proxy = proxy
271+
if err != nil {
272+
return nil, fmt.Errorf("failed to connect to bastion host '%v': %w", proxy, err)
273+
}
258274
}
259275
}
260276

261-
if cfg.User == "" {
277+
// cfg.User value defaults to u.User.Username()
278+
if sshcfg != nil {
262279
sshu, err := sshcfg.Get(target, "User")
263-
log.Printf("[DEBUG] SSH User for target '%v' is '%v'", target, sshu)
264280
if err != nil {
265-
log.Printf("[DEBUG] ssh user: using current login")
266-
u, err := user.Current()
267-
if err != nil {
268-
return nil, fmt.Errorf("unable to get username: %w", err)
269-
}
270-
sshu = u.Username
281+
log.Printf("[DEBUG] ssh user for target '%v' is overridden to '%v'", target, sshu)
282+
cfg.User = sshu
271283
}
272-
cfg.User = sshu
273284
}
274285

286+
275287
cfg.Auth = u.parseAuthMethods(target, sshcfg)
276288
if len(cfg.Auth) < 1 {
277289
return nil, fmt.Errorf("could not configure SSH authentication methods")
278290
}
279291

280292
if bastion != nil {
281293
// if this is a proxied connection, we want to dial through the bastion host
282-
log.Printf("[INFO] SSH connecting to '%v' (%v) through bastion host '%v'", target, hostName, proxy)
294+
log.Printf("[INFO] SSH connecting to '%v' (%v) through bastion host '%v'", target, hostName, bastion_proxy)
283295
// Dial a connection to the service host, from the bastion
284296
conn, err := bastion.Dial("tcp", net.JoinHostPort(hostName, port))
285297
if err != nil {

0 commit comments

Comments
 (0)