IdentityFile among others supports being provided multiple times and aggregated across, potentially, multiple files. Support that workflow by adding GetAll and GetAllStrict alongside the current functions.
187 lines
8.8 KiB
Go
187 lines
8.8 KiB
Go
package ssh_config
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Default returns the default value for the given keyword, for example "22" if
|
|
// the keyword is "Port". Default returns the empty string if the keyword has no
|
|
// default, or if the keyword is unknown. Keyword matching is case-insensitive.
|
|
//
|
|
// Default values are provided by OpenSSH_7.4p1 on a Mac.
|
|
func Default(keyword string) string {
|
|
return defaults[strings.ToLower(keyword)]
|
|
}
|
|
|
|
// Arguments where the value must be "yes" or "no" and *only* yes or no.
|
|
var yesnos = map[string]bool{
|
|
strings.ToLower("BatchMode"): true,
|
|
strings.ToLower("CanonicalizeFallbackLocal"): true,
|
|
strings.ToLower("ChallengeResponseAuthentication"): true,
|
|
strings.ToLower("CheckHostIP"): true,
|
|
strings.ToLower("ClearAllForwardings"): true,
|
|
strings.ToLower("Compression"): true,
|
|
strings.ToLower("EnableSSHKeysign"): true,
|
|
strings.ToLower("ExitOnForwardFailure"): true,
|
|
strings.ToLower("ForwardAgent"): true,
|
|
strings.ToLower("ForwardX11"): true,
|
|
strings.ToLower("ForwardX11Trusted"): true,
|
|
strings.ToLower("GatewayPorts"): true,
|
|
strings.ToLower("GSSAPIAuthentication"): true,
|
|
strings.ToLower("GSSAPIDelegateCredentials"): true,
|
|
strings.ToLower("HostbasedAuthentication"): true,
|
|
strings.ToLower("IdentitiesOnly"): true,
|
|
strings.ToLower("KbdInteractiveAuthentication"): true,
|
|
strings.ToLower("NoHostAuthenticationForLocalhost"): true,
|
|
strings.ToLower("PasswordAuthentication"): true,
|
|
strings.ToLower("PermitLocalCommand"): true,
|
|
strings.ToLower("PubkeyAuthentication"): true,
|
|
strings.ToLower("RhostsRSAAuthentication"): true,
|
|
strings.ToLower("RSAAuthentication"): true,
|
|
strings.ToLower("StreamLocalBindUnlink"): true,
|
|
strings.ToLower("TCPKeepAlive"): true,
|
|
strings.ToLower("UseKeychain"): true,
|
|
strings.ToLower("UsePrivilegedPort"): true,
|
|
strings.ToLower("VisualHostKey"): true,
|
|
}
|
|
|
|
var uints = map[string]bool{
|
|
strings.ToLower("CanonicalizeMaxDots"): true,
|
|
strings.ToLower("CompressionLevel"): true, // 1 to 9
|
|
strings.ToLower("ConnectionAttempts"): true,
|
|
strings.ToLower("ConnectTimeout"): true,
|
|
strings.ToLower("NumberOfPasswordPrompts"): true,
|
|
strings.ToLower("Port"): true,
|
|
strings.ToLower("ServerAliveCountMax"): true,
|
|
strings.ToLower("ServerAliveInterval"): true,
|
|
}
|
|
|
|
func mustBeYesOrNo(lkey string) bool {
|
|
return yesnos[lkey]
|
|
}
|
|
|
|
func mustBeUint(lkey string) bool {
|
|
return uints[lkey]
|
|
}
|
|
|
|
func validate(key, val string) error {
|
|
lkey := strings.ToLower(key)
|
|
if mustBeYesOrNo(lkey) && (val != "yes" && val != "no") {
|
|
return fmt.Errorf("ssh_config: value for key %q must be 'yes' or 'no', got %q", key, val)
|
|
}
|
|
if mustBeUint(lkey) {
|
|
_, err := strconv.ParseUint(val, 10, 64)
|
|
if err != nil {
|
|
return fmt.Errorf("ssh_config: %v", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var defaults = map[string]string{
|
|
strings.ToLower("AddKeysToAgent"): "no",
|
|
strings.ToLower("AddressFamily"): "any",
|
|
strings.ToLower("BatchMode"): "no",
|
|
strings.ToLower("CanonicalizeFallbackLocal"): "yes",
|
|
strings.ToLower("CanonicalizeHostname"): "no",
|
|
strings.ToLower("CanonicalizeMaxDots"): "1",
|
|
strings.ToLower("ChallengeResponseAuthentication"): "yes",
|
|
strings.ToLower("CheckHostIP"): "yes",
|
|
// TODO is this still the correct cipher
|
|
strings.ToLower("Cipher"): "3des",
|
|
strings.ToLower("Ciphers"): "chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,aes128-cbc,aes192-cbc,aes256-cbc",
|
|
strings.ToLower("ClearAllForwardings"): "no",
|
|
strings.ToLower("Compression"): "no",
|
|
strings.ToLower("CompressionLevel"): "6",
|
|
strings.ToLower("ConnectionAttempts"): "1",
|
|
strings.ToLower("ControlMaster"): "no",
|
|
strings.ToLower("EnableSSHKeysign"): "no",
|
|
strings.ToLower("EscapeChar"): "~",
|
|
strings.ToLower("ExitOnForwardFailure"): "no",
|
|
strings.ToLower("FingerprintHash"): "sha256",
|
|
strings.ToLower("ForwardAgent"): "no",
|
|
strings.ToLower("ForwardX11"): "no",
|
|
strings.ToLower("ForwardX11Timeout"): "20m",
|
|
strings.ToLower("ForwardX11Trusted"): "no",
|
|
strings.ToLower("GatewayPorts"): "no",
|
|
strings.ToLower("GlobalKnownHostsFile"): "/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2",
|
|
strings.ToLower("GSSAPIAuthentication"): "no",
|
|
strings.ToLower("GSSAPIDelegateCredentials"): "no",
|
|
strings.ToLower("HashKnownHosts"): "no",
|
|
strings.ToLower("HostbasedAuthentication"): "no",
|
|
|
|
strings.ToLower("HostbasedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa",
|
|
strings.ToLower("HostKeyAlgorithms"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa",
|
|
// HostName has a dynamic default (the value passed at the command line).
|
|
|
|
strings.ToLower("IdentitiesOnly"): "no",
|
|
strings.ToLower("IdentityFile"): "~/.ssh/identity",
|
|
|
|
// IPQoS has a dynamic default based on interactive or non-interactive
|
|
// sessions.
|
|
|
|
strings.ToLower("KbdInteractiveAuthentication"): "yes",
|
|
|
|
strings.ToLower("KexAlgorithms"): "curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1",
|
|
strings.ToLower("LogLevel"): "INFO",
|
|
strings.ToLower("MACs"): "umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1",
|
|
|
|
strings.ToLower("NoHostAuthenticationForLocalhost"): "no",
|
|
strings.ToLower("NumberOfPasswordPrompts"): "3",
|
|
strings.ToLower("PasswordAuthentication"): "yes",
|
|
strings.ToLower("PermitLocalCommand"): "no",
|
|
strings.ToLower("Port"): "22",
|
|
|
|
strings.ToLower("PreferredAuthentications"): "gssapi-with-mic,hostbased,publickey,keyboard-interactive,password",
|
|
strings.ToLower("Protocol"): "2",
|
|
strings.ToLower("ProxyUseFdpass"): "no",
|
|
strings.ToLower("PubkeyAcceptedKeyTypes"): "ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,ssh-rsa",
|
|
strings.ToLower("PubkeyAuthentication"): "yes",
|
|
strings.ToLower("RekeyLimit"): "default none",
|
|
strings.ToLower("RhostsRSAAuthentication"): "no",
|
|
strings.ToLower("RSAAuthentication"): "yes",
|
|
|
|
strings.ToLower("ServerAliveCountMax"): "3",
|
|
strings.ToLower("ServerAliveInterval"): "0",
|
|
strings.ToLower("StreamLocalBindMask"): "0177",
|
|
strings.ToLower("StreamLocalBindUnlink"): "no",
|
|
strings.ToLower("StrictHostKeyChecking"): "ask",
|
|
strings.ToLower("TCPKeepAlive"): "yes",
|
|
strings.ToLower("Tunnel"): "no",
|
|
strings.ToLower("TunnelDevice"): "any:any",
|
|
strings.ToLower("UpdateHostKeys"): "no",
|
|
strings.ToLower("UseKeychain"): "no",
|
|
strings.ToLower("UsePrivilegedPort"): "no",
|
|
|
|
strings.ToLower("UserKnownHostsFile"): "~/.ssh/known_hosts ~/.ssh/known_hosts2",
|
|
strings.ToLower("VerifyHostKeyDNS"): "no",
|
|
strings.ToLower("VisualHostKey"): "no",
|
|
strings.ToLower("XAuthLocation"): "/usr/X11R6/bin/xauth",
|
|
}
|
|
|
|
// these identities are used for SSH protocol 2
|
|
var defaultProtocol2Identities = []string{
|
|
"~/.ssh/id_dsa",
|
|
"~/.ssh/id_ecdsa",
|
|
"~/.ssh/id_ed25519",
|
|
"~/.ssh/id_rsa",
|
|
}
|
|
|
|
// these directives support multiple items that can be collected
|
|
// across multiple files
|
|
var pluralDirectives = map[string]bool{
|
|
"CertificateFile": true,
|
|
"IdentityFile": true,
|
|
"DynamicForward": true,
|
|
"RemoteForward": true,
|
|
"SendEnv": true,
|
|
"SetEnv": true,
|
|
}
|
|
|
|
// SupportsMultiple reports whether a directive can be specified multiple times.
|
|
func SupportsMultiple(key string) bool {
|
|
return pluralDirectives[strings.ToLower(key)]
|
|
}
|