main
1package ssh_config
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7)
8
9// Default returns the default value for the given keyword, for example "22" if
10// the keyword is "Port". Default returns the empty string if the keyword has no
11// default, or if the keyword is unknown. Keyword matching is case-insensitive.
12//
13// Default values are provided by OpenSSH_7.4p1 on a Mac.
14func Default(keyword string) string {
15 return defaults[strings.ToLower(keyword)]
16}
17
18// Arguments where the value must be "yes" or "no" and *only* yes or no.
19var yesnos = map[string]bool{
20 strings.ToLower("BatchMode"): true,
21 strings.ToLower("CanonicalizeFallbackLocal"): true,
22 strings.ToLower("ChallengeResponseAuthentication"): true,
23 strings.ToLower("CheckHostIP"): true,
24 strings.ToLower("ClearAllForwardings"): true,
25 strings.ToLower("Compression"): true,
26 strings.ToLower("EnableSSHKeysign"): true,
27 strings.ToLower("ExitOnForwardFailure"): true,
28 strings.ToLower("ForwardAgent"): true,
29 strings.ToLower("ForwardX11"): true,
30 strings.ToLower("ForwardX11Trusted"): true,
31 strings.ToLower("GatewayPorts"): true,
32 strings.ToLower("GSSAPIAuthentication"): true,
33 strings.ToLower("GSSAPIDelegateCredentials"): true,
34 strings.ToLower("HostbasedAuthentication"): true,
35 strings.ToLower("IdentitiesOnly"): true,
36 strings.ToLower("KbdInteractiveAuthentication"): true,
37 strings.ToLower("NoHostAuthenticationForLocalhost"): true,
38 strings.ToLower("PasswordAuthentication"): true,
39 strings.ToLower("PermitLocalCommand"): true,
40 strings.ToLower("PubkeyAuthentication"): true,
41 strings.ToLower("RhostsRSAAuthentication"): true,
42 strings.ToLower("RSAAuthentication"): true,
43 strings.ToLower("StreamLocalBindUnlink"): true,
44 strings.ToLower("TCPKeepAlive"): true,
45 strings.ToLower("UseKeychain"): true,
46 strings.ToLower("UsePrivilegedPort"): true,
47 strings.ToLower("VisualHostKey"): true,
48}
49
50var uints = map[string]bool{
51 strings.ToLower("CanonicalizeMaxDots"): true,
52 strings.ToLower("CompressionLevel"): true, // 1 to 9
53 strings.ToLower("ConnectionAttempts"): true,
54 strings.ToLower("ConnectTimeout"): true,
55 strings.ToLower("NumberOfPasswordPrompts"): true,
56 strings.ToLower("Port"): true,
57 strings.ToLower("ServerAliveCountMax"): true,
58 strings.ToLower("ServerAliveInterval"): true,
59}
60
61func mustBeYesOrNo(lkey string) bool {
62 return yesnos[lkey]
63}
64
65func mustBeUint(lkey string) bool {
66 return uints[lkey]
67}
68
69func validate(key, val string) error {
70 lkey := strings.ToLower(key)
71 if mustBeYesOrNo(lkey) && (val != "yes" && val != "no") {
72 return fmt.Errorf("ssh_config: value for key %q must be 'yes' or 'no', got %q", key, val)
73 }
74 if mustBeUint(lkey) {
75 _, err := strconv.ParseUint(val, 10, 64)
76 if err != nil {
77 return fmt.Errorf("ssh_config: %v", err)
78 }
79 }
80 return nil
81}
82
83var defaults = map[string]string{
84 strings.ToLower("AddKeysToAgent"): "no",
85 strings.ToLower("AddressFamily"): "any",
86 strings.ToLower("BatchMode"): "no",
87 strings.ToLower("CanonicalizeFallbackLocal"): "yes",
88 strings.ToLower("CanonicalizeHostname"): "no",
89 strings.ToLower("CanonicalizeMaxDots"): "1",
90 strings.ToLower("ChallengeResponseAuthentication"): "yes",
91 strings.ToLower("CheckHostIP"): "yes",
92 // TODO is this still the correct cipher
93 strings.ToLower("Cipher"): "3des",
94 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",
95 strings.ToLower("ClearAllForwardings"): "no",
96 strings.ToLower("Compression"): "no",
97 strings.ToLower("CompressionLevel"): "6",
98 strings.ToLower("ConnectionAttempts"): "1",
99 strings.ToLower("ControlMaster"): "no",
100 strings.ToLower("EnableSSHKeysign"): "no",
101 strings.ToLower("EscapeChar"): "~",
102 strings.ToLower("ExitOnForwardFailure"): "no",
103 strings.ToLower("FingerprintHash"): "sha256",
104 strings.ToLower("ForwardAgent"): "no",
105 strings.ToLower("ForwardX11"): "no",
106 strings.ToLower("ForwardX11Timeout"): "20m",
107 strings.ToLower("ForwardX11Trusted"): "no",
108 strings.ToLower("GatewayPorts"): "no",
109 strings.ToLower("GlobalKnownHostsFile"): "/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2",
110 strings.ToLower("GSSAPIAuthentication"): "no",
111 strings.ToLower("GSSAPIDelegateCredentials"): "no",
112 strings.ToLower("HashKnownHosts"): "no",
113 strings.ToLower("HostbasedAuthentication"): "no",
114
115 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",
116 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",
117 // HostName has a dynamic default (the value passed at the command line).
118
119 strings.ToLower("IdentitiesOnly"): "no",
120 strings.ToLower("IdentityFile"): "~/.ssh/identity",
121
122 // IPQoS has a dynamic default based on interactive or non-interactive
123 // sessions.
124
125 strings.ToLower("KbdInteractiveAuthentication"): "yes",
126
127 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",
128 strings.ToLower("LogLevel"): "INFO",
129 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",
130
131 strings.ToLower("NoHostAuthenticationForLocalhost"): "no",
132 strings.ToLower("NumberOfPasswordPrompts"): "3",
133 strings.ToLower("PasswordAuthentication"): "yes",
134 strings.ToLower("PermitLocalCommand"): "no",
135 strings.ToLower("Port"): "22",
136
137 strings.ToLower("PreferredAuthentications"): "gssapi-with-mic,hostbased,publickey,keyboard-interactive,password",
138 strings.ToLower("Protocol"): "2",
139 strings.ToLower("ProxyUseFdpass"): "no",
140 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",
141 strings.ToLower("PubkeyAuthentication"): "yes",
142 strings.ToLower("RekeyLimit"): "default none",
143 strings.ToLower("RhostsRSAAuthentication"): "no",
144 strings.ToLower("RSAAuthentication"): "yes",
145
146 strings.ToLower("ServerAliveCountMax"): "3",
147 strings.ToLower("ServerAliveInterval"): "0",
148 strings.ToLower("StreamLocalBindMask"): "0177",
149 strings.ToLower("StreamLocalBindUnlink"): "no",
150 strings.ToLower("StrictHostKeyChecking"): "ask",
151 strings.ToLower("TCPKeepAlive"): "yes",
152 strings.ToLower("Tunnel"): "no",
153 strings.ToLower("TunnelDevice"): "any:any",
154 strings.ToLower("UpdateHostKeys"): "no",
155 strings.ToLower("UseKeychain"): "no",
156 strings.ToLower("UsePrivilegedPort"): "no",
157
158 strings.ToLower("UserKnownHostsFile"): "~/.ssh/known_hosts ~/.ssh/known_hosts2",
159 strings.ToLower("VerifyHostKeyDNS"): "no",
160 strings.ToLower("VisualHostKey"): "no",
161 strings.ToLower("XAuthLocation"): "/usr/X11R6/bin/xauth",
162}
163
164// these identities are used for SSH protocol 2
165var defaultProtocol2Identities = []string{
166 "~/.ssh/id_dsa",
167 "~/.ssh/id_ecdsa",
168 "~/.ssh/id_ed25519",
169 "~/.ssh/id_rsa",
170}
171
172// these directives support multiple items that can be collected
173// across multiple files
174var pluralDirectives = map[string]bool{
175 "CertificateFile": true,
176 "IdentityFile": true,
177 "DynamicForward": true,
178 "RemoteForward": true,
179 "SendEnv": true,
180 "SetEnv": true,
181}
182
183// SupportsMultiple reports whether a directive can be specified multiple times.
184func SupportsMultiple(key string) bool {
185 return pluralDirectives[strings.ToLower(key)]
186}