Update IdentityFile Defaults to Match Documentation (#4)

Credit to @virtuald for the original implementation of this fix.

* Add support for retrieving all IdentityFile directives via DefaultAll

* fix: set IdentityFile defaults to match man page

The existing default IdentityFile list was incomplete and out of order.
This updates it to match the defaults listed here:
https://man7.org/linux/man-pages/man5/ssh_config.5.html

---------

Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com>
This commit is contained in:
Sylvie Crowe
2024-03-05 20:10:34 -08:00
committed by GitHub
co-authored by Dustin Spicuzza
parent cba6b6a60f
commit 17e2087ebd
3 changed files with 43 additions and 10 deletions
+17 -5
View File
@@ -49,6 +49,13 @@ var _ = version
type configFinder func() string
type config interface {
getinternal(alias, key string) string
}
var _ config = &UserSettings{}
var _ config = &Config{}
// UserSettings checks ~/.ssh and /etc/ssh for configuration files. The config
// files are parsed and cached the first time Get() or GetStrict() is called.
type UserSettings struct {
@@ -189,6 +196,10 @@ func (u *UserSettings) Get(alias, key string) string {
return val
}
func (u *UserSettings) getinternal(alias, key string) string {
return u.Get(alias, key)
}
// GetAll retrieves zero or more directives for key for the given alias. GetAll
// returns nil if no value was found, or if IgnoreErrors is false and we could
// not parse the configuration file. Use GetStrict to disambiguate the latter
@@ -259,11 +270,7 @@ func (u *UserSettings) GetAllStrict(alias, key string) ([]string, error) {
if err2 != nil || val2 != nil {
return val2, err2
}
// TODO: IdentityFile has multiple default values that we should return.
if def := Default(key); def != "" {
return []string{def}, nil
}
return []string{}, nil
return DefaultAll(key, alias, u), nil
}
// ConfigFinder will invoke f to try to find a ssh config file in a custom
@@ -425,6 +432,11 @@ func (c *Config) Get(alias, key string) (string, error) {
return "", nil
}
func (c *Config) getinternal(alias, key string) string {
v, _ := c.Get(alias, key)
return v
}
// GetAll returns all values in the configuration that match the alias and
// contains key, or nil if none are present.
func (c *Config) GetAll(alias, key string) ([]string, error) {
+1 -2
View File
@@ -111,8 +111,7 @@ func TestGetIdentities(t *testing.T) {
t.Errorf("expected nil err, got %v", err)
}
if len(val) != len(defaultProtocol2Identities) {
// TODO: return the right values here.
log.Printf("expected defaults, got %v", val)
t.Errorf("expected defaults, got %v", val)
} else {
for i, v := range defaultProtocol2Identities {
if val[i] != v {
+25 -3
View File
@@ -15,6 +15,26 @@ func Default(keyword string) string {
return defaults[strings.ToLower(keyword)]
}
// DefaultAll returns the default value for the given keyword, but as a slice. If
// there is no default for the keyword, nil is returned.
//
// Some multi-valued settings have different defaults based on other settings, so
// you must provide the host alias and a config to retrieve a setting from
func DefaultAll(keyword string, alias string, cfg config) []string {
if strings.ToLower(keyword) == "identityfile" && cfg.getinternal(alias, "Protocol") == "2" {
def := make([]string, len(defaultProtocol2Identities))
copy(def, defaultProtocol2Identities)
return def
}
def := Default(keyword)
if def != "" {
return []string{def}
}
return nil
}
// Arguments where the value must be "yes" or "no" and *only* yes or no.
var yesnos = map[string]bool{
strings.ToLower("BatchMode"): true,
@@ -163,10 +183,12 @@ var defaults = map[string]string{
// these identities are used for SSH protocol 2
var defaultProtocol2Identities = []string{
"~/.ssh/id_dsa",
"~/.ssh/id_ecdsa",
"~/.ssh/id_ed25519",
"~/.ssh/id_rsa",
"~/.ssh/id_ecdsa",
"~/.ssh/id_ecdsa_sk",
"~/.ssh/id_ed25519",
"~/.ssh/id_ed25519_sk",
"~/.ssh/id_dsa",
}
// these directives support multiple items that can be collected