LEFT | RIGHT |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "bytes" | 8 "bytes" |
9 "crypto/rand" | 9 "crypto/rand" |
10 "errors" | 10 "errors" |
(...skipping 15 matching lines...) Expand all Loading... |
26 // NoClientAuth is true if clients are allowed to connect without | 26 // NoClientAuth is true if clients are allowed to connect without |
27 // authenticating. | 27 // authenticating. |
28 NoClientAuth bool | 28 NoClientAuth bool |
29 | 29 |
30 // PasswordCallback, if non-nil, is called when a user attempts to | 30 // PasswordCallback, if non-nil, is called when a user attempts to |
31 // authenticate using a password. It may be called concurrently from | 31 // authenticate using a password. It may be called concurrently from |
32 // several goroutines. | 32 // several goroutines. |
33 PasswordCallback func(conn *ServerConn, user, password string) bool | 33 PasswordCallback func(conn *ServerConn, user, password string) bool |
34 | 34 |
35 // PublicKeyCallback, if non-nil, is called when a client attempts publi
c | 35 // PublicKeyCallback, if non-nil, is called when a client attempts publi
c |
36 » // key authentication. It must return true iff the given public key is | 36 » // key authentication. It must return true if the given public key is |
37 // valid for the given user. | 37 // valid for the given user. |
38 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt
e) bool | 38 PublicKeyCallback func(conn *ServerConn, user, algo string, pubkey []byt
e) bool |
39 | 39 |
40 // KeyboardInteractiveCallback, if non-nil, is called when | 40 // KeyboardInteractiveCallback, if non-nil, is called when |
41 // keyboard-interactive authentication is selected (RFC | 41 // keyboard-interactive authentication is selected (RFC |
42 // 4256). The client object's Challenge function should be | 42 // 4256). The client object's Challenge function should be |
43 // used to query the user. The callback may offer multiple | 43 // used to query the user. The callback may offer multiple |
44 // Challenge rounds. To avoid information leaks, the client | 44 // Challenge rounds. To avoid information leaks, the client |
45 // should be presented a challenge even if the user is | 45 // should be presented a challenge even if the user is |
46 // unknown. | 46 // unknown. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 type cachedPubKey struct { | 88 type cachedPubKey struct { |
89 user, algo string | 89 user, algo string |
90 pubKey []byte | 90 pubKey []byte |
91 result bool | 91 result bool |
92 } | 92 } |
93 | 93 |
94 const maxCachedPubKeys = 16 | 94 const maxCachedPubKeys = 16 |
95 | 95 |
96 // A ServerConn represents an incoming connection. | 96 // A ServerConn represents an incoming connection. |
97 type ServerConn struct { | 97 type ServerConn struct { |
98 » *transport | 98 » transport *transport |
99 » config *ServerConfig | 99 » config *ServerConfig |
100 | 100 |
101 // cachedPubKeys contains the cache results of tests for public keys. | 101 // cachedPubKeys contains the cache results of tests for public keys. |
102 // Since SSH clients will query whether a public key is acceptable | 102 // Since SSH clients will query whether a public key is acceptable |
103 // before attempting to authenticate with it, we end up with duplicate | 103 // before attempting to authenticate with it, we end up with duplicate |
104 // queries for public key validity. | 104 // queries for public key validity. |
105 cachedPubKeys []cachedPubKey | 105 cachedPubKeys []cachedPubKey |
106 | 106 |
107 // User holds the successfully authenticated user name. | 107 // User holds the successfully authenticated user name. |
108 // It is empty if no authentication is used. It is populated before | 108 // It is empty if no authentication is used. It is populated before |
109 // any authentication callback is called and not assigned to after that. | 109 // any authentication callback is called and not assigned to after that. |
110 User string | 110 User string |
111 | 111 |
112 // ClientVersion is the client's version, populated after | 112 // ClientVersion is the client's version, populated after |
113 // Handshake is called. It should not be modified. | 113 // Handshake is called. It should not be modified. |
114 ClientVersion []byte | 114 ClientVersion []byte |
115 | 115 |
| 116 // Our version. |
| 117 serverVersion []byte |
| 118 |
116 // Initial H used for the session ID. Once assigned this must not change | 119 // Initial H used for the session ID. Once assigned this must not change |
117 // even during subsequent key exchanges. | 120 // even during subsequent key exchanges. |
118 sessionId []byte | 121 sessionId []byte |
119 mux *mux | 122 mux *mux |
120 } | 123 } |
121 | 124 |
122 // Server returns a new SSH server connection | 125 // Server returns a new SSH server connection |
123 // using c as the underlying transport. | 126 // using c as the underlying transport. |
124 func Server(c net.Conn, config *ServerConfig) *ServerConn { | 127 func Server(c net.Conn, config *ServerConfig) *ServerConn { |
125 » tr := newTransport(c, config.rand()) | 128 » tr := newTransport(c, config.rand(), false /* not client */) |
126 return &ServerConn{ | 129 return &ServerConn{ |
127 transport: tr, | 130 transport: tr, |
128 config: config, | 131 config: config, |
129 mux: newMux(tr), | |
130 } | 132 } |
131 } | 133 } |
132 | 134 |
133 // signAndMarshal signs the data with the appropriate algorithm, | 135 // signAndMarshal signs the data with the appropriate algorithm, |
134 // and serializes the result in SSH wire format. | 136 // and serializes the result in SSH wire format. |
135 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { | 137 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { |
136 sig, err := k.Sign(rand, data) | 138 sig, err := k.Sign(rand, data) |
137 if err != nil { | 139 if err != nil { |
138 return nil, err | 140 return nil, err |
139 } | 141 } |
140 | 142 |
141 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil | 143 return serializeSignature(k.PublicKey().PrivateKeyAlgo(), sig), nil |
142 } | 144 } |
143 | 145 |
144 // serverVersion is the fixed identification string that Server will use. | 146 // Close closes the connection. |
145 var serverVersion = []byte("SSH-2.0-Go\r\n") | 147 func (s *ServerConn) Close() error { return s.transport.Close() } |
| 148 |
| 149 // LocalAddr returns the local network address. |
| 150 func (c *ServerConn) LocalAddr() net.Addr { return c.transport.LocalAddr() } |
| 151 |
| 152 // RemoteAddr returns the remote network address. |
| 153 func (c *ServerConn) RemoteAddr() net.Addr { return c.transport.RemoteAddr() } |
146 | 154 |
147 // Handshake performs an SSH transport and client authentication on the given Se
rverConn. | 155 // Handshake performs an SSH transport and client authentication on the given Se
rverConn. |
148 func (s *ServerConn) Handshake() (err error) { | 156 func (s *ServerConn) Handshake() error { |
149 » if _, err = s.Write(serverVersion); err != nil { | 157 » var err error |
150 » » return | 158 » s.serverVersion = []byte(packageVersion) |
151 » } | 159 » s.ClientVersion, err = exchangeVersions(s.transport.Conn, s.serverVersio
n) |
152 » if err := s.Flush(); err != nil { | 160 » if err != nil { |
153 » » return err | 161 » » return err |
154 » } | 162 » } |
155 | 163 » if err := s.clientInitHandshake(nil, nil); err != nil { |
156 » s.ClientVersion, err = readVersion(s) | 164 » » return err |
157 » if err != nil { | |
158 » » return | |
159 » } | |
160 » if err = s.clientInitHandshake(nil, nil); err != nil { | |
161 » » return | |
162 } | 165 } |
163 | 166 |
164 var packet []byte | 167 var packet []byte |
165 » if packet, err = s.readPacket(); err != nil { | 168 » if packet, err = s.transport.readPacket(); err != nil { |
166 » » return | 169 » » return err |
167 } | 170 } |
168 var serviceRequest serviceRequestMsg | 171 var serviceRequest serviceRequestMsg |
169 » if err = unmarshal(&serviceRequest, packet, msgServiceRequest); err != n
il { | 172 » if err := unmarshal(&serviceRequest, packet, msgServiceRequest); err !=
nil { |
170 » » return | 173 » » return err |
171 } | 174 } |
172 if serviceRequest.Service != serviceUserAuth { | 175 if serviceRequest.Service != serviceUserAuth { |
173 return errors.New("ssh: requested service '" + serviceRequest.Se
rvice + "' before authenticating") | 176 return errors.New("ssh: requested service '" + serviceRequest.Se
rvice + "' before authenticating") |
174 } | 177 } |
175 serviceAccept := serviceAcceptMsg{ | 178 serviceAccept := serviceAcceptMsg{ |
176 Service: serviceUserAuth, | 179 Service: serviceUserAuth, |
177 } | 180 } |
178 » if err = s.writePacket(marshal(msgServiceAccept, serviceAccept)); err !=
nil { | 181 » if err := s.transport.writePacket(marshal(msgServiceAccept, serviceAccep
t)); err != nil { |
179 » » return | 182 » » return err |
180 » } | 183 » } |
181 | 184 |
182 » if err = s.authenticate(s.sessionId); err != nil { | 185 » if err := s.authenticate(); err != nil { |
183 » » return | 186 » » return err |
184 » } | 187 » } |
185 | 188 |
| 189 » s.mux = newMux(s.transport) |
| 190 » go s.handleGlobalRequests() |
186 go s.mux.Loop() | 191 go s.mux.Loop() |
187 » go s.handleGlobalRequests() | 192 » return err |
188 » return | |
189 } | 193 } |
190 | 194 |
191 func (s *ServerConn) handleGlobalRequests() { | 195 func (s *ServerConn) handleGlobalRequests() { |
192 » for r := range s.mux.ReceivedRequests() { | 196 » for r := range s.mux.incomingRequests { |
193 if r.WantReply { | 197 if r.WantReply { |
194 s.mux.AckRequest(false, nil) | 198 s.mux.AckRequest(false, nil) |
195 } | 199 } |
196 } | 200 } |
197 } | 201 } |
198 | 202 |
199 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni
tPacket []byte) (err error) { | 203 func (s *ServerConn) clientInitHandshake(clientKexInit *kexInitMsg, clientKexIni
tPacket []byte) (err error) { |
200 serverKexInit := kexInitMsg{ | 204 serverKexInit := kexInitMsg{ |
201 KexAlgos: s.config.Crypto.kexes(), | 205 KexAlgos: s.config.Crypto.kexes(), |
202 CiphersClientServer: s.config.Crypto.ciphers(), | 206 CiphersClientServer: s.config.Crypto.ciphers(), |
203 CiphersServerClient: s.config.Crypto.ciphers(), | 207 CiphersServerClient: s.config.Crypto.ciphers(), |
204 MACsClientServer: s.config.Crypto.macs(), | 208 MACsClientServer: s.config.Crypto.macs(), |
205 MACsServerClient: s.config.Crypto.macs(), | 209 MACsServerClient: s.config.Crypto.macs(), |
206 CompressionClientServer: supportedCompressions, | 210 CompressionClientServer: supportedCompressions, |
207 CompressionServerClient: supportedCompressions, | 211 CompressionServerClient: supportedCompressions, |
208 } | 212 } |
209 for _, k := range s.config.hostKeys { | 213 for _, k := range s.config.hostKeys { |
210 serverKexInit.ServerHostKeyAlgos = append( | 214 serverKexInit.ServerHostKeyAlgos = append( |
211 serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKe
yAlgo()) | 215 serverKexInit.ServerHostKeyAlgos, k.PublicKey().PublicKe
yAlgo()) |
212 } | 216 } |
213 | 217 |
214 serverKexInitPacket := marshal(msgKexInit, serverKexInit) | 218 serverKexInitPacket := marshal(msgKexInit, serverKexInit) |
215 » if err = s.writePacket(serverKexInitPacket); err != nil { | 219 » if err = s.transport.writePacket(serverKexInitPacket); err != nil { |
216 return | 220 return |
217 } | 221 } |
218 | 222 |
219 if clientKexInitPacket == nil { | 223 if clientKexInitPacket == nil { |
220 clientKexInit = new(kexInitMsg) | 224 clientKexInit = new(kexInitMsg) |
221 » » if clientKexInitPacket, err = s.readPacket(); err != nil { | 225 » » if clientKexInitPacket, err = s.transport.readPacket(); err != n
il { |
222 return | 226 return |
223 } | 227 } |
224 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni
t); err != nil { | 228 if err = unmarshal(clientKexInit, clientKexInitPacket, msgKexIni
t); err != nil { |
225 return | 229 return |
226 } | 230 } |
227 } | 231 } |
228 | 232 |
229 » kexAlgo, hostKeyAlgo, ok := findAgreedAlgorithms(s.transport, clientKexI
nit, &serverKexInit) | 233 » algs := findAgreedAlgorithms(clientKexInit, &serverKexInit) |
230 » if !ok { | 234 » if algs == nil { |
231 return errors.New("ssh: no common algorithms") | 235 return errors.New("ssh: no common algorithms") |
232 } | 236 } |
233 » if clientKexInit.FirstKexFollows && kexAlgo != clientKexInit.KexAlgos[0]
{ | 237 |
| 238 » if clientKexInit.FirstKexFollows && algs.kex != clientKexInit.KexAlgos[0
] { |
234 // The client sent a Kex message for the wrong algorithm, | 239 // The client sent a Kex message for the wrong algorithm, |
235 // which we have to ignore. | 240 // which we have to ignore. |
236 » » if _, err = s.readPacket(); err != nil { | 241 » » if _, err = s.transport.readPacket(); err != nil { |
237 return | 242 return |
238 } | 243 } |
239 } | 244 } |
240 | 245 |
241 var hostKey Signer | 246 var hostKey Signer |
242 for _, k := range s.config.hostKeys { | 247 for _, k := range s.config.hostKeys { |
243 » » if hostKeyAlgo == k.PublicKey().PublicKeyAlgo() { | 248 » » if algs.hostKey == k.PublicKey().PublicKeyAlgo() { |
244 hostKey = k | 249 hostKey = k |
245 } | 250 } |
246 } | 251 } |
247 | 252 |
248 » kex, ok := kexAlgoMap[kexAlgo] | 253 » kex, ok := kexAlgoMap[algs.kex] |
249 if !ok { | 254 if !ok { |
250 » » return fmt.Errorf("ssh: unexpected key exchange algorithm %v", k
exAlgo) | 255 » » return fmt.Errorf("ssh: unexpected key exchange algorithm %v", a
lgs.kex) |
251 } | 256 } |
252 | 257 |
253 magics := handshakeMagics{ | 258 magics := handshakeMagics{ |
254 » » serverVersion: serverVersion[:len(serverVersion)-2], | 259 » » serverVersion: s.serverVersion, |
255 clientVersion: s.ClientVersion, | 260 clientVersion: s.ClientVersion, |
256 serverKexInit: marshal(msgKexInit, serverKexInit), | 261 serverKexInit: marshal(msgKexInit, serverKexInit), |
257 clientKexInit: clientKexInitPacket, | 262 clientKexInit: clientKexInitPacket, |
258 } | 263 } |
259 » result, err := kex.Server(s, s.config.rand(), &magics, hostKey) | 264 » result, err := kex.Server(s.transport, s.config.rand(), &magics, hostKey
) |
260 » if err != nil { | 265 » if err != nil { |
261 » » return err | 266 » » return err |
262 » } | 267 » } |
263 | 268 |
264 » // sessionId must only be assigned during initial handshake. | 269 » if err = s.transport.prepareKeyChange(algs, result); err != nil { |
265 » if s.sessionId == nil { | 270 » » return err |
266 » » s.sessionId = result.H | 271 » } |
267 » } | 272 |
268 | 273 » if err = s.transport.writePacket([]byte{msgNewKeys}); err != nil { |
269 » var packet []byte | |
270 | |
271 » if err = s.writePacket([]byte{msgNewKeys}); err != nil { | |
272 return | 274 return |
273 } | 275 } |
274 » if err = s.transport.writer.setupKeys(serverKeys, result.K, result.H, s.
sessionId, kex.Hash()); err != nil { | 276 » if packet, err := s.transport.readPacket(); err != nil { |
275 » » return | 277 » » return err |
276 » } | 278 » } else if packet[0] != msgNewKeys { |
277 | |
278 » if packet, err = s.readPacket(); err != nil { | |
279 » » return | |
280 » } | |
281 » if packet[0] != msgNewKeys { | |
282 return UnexpectedMessageError{msgNewKeys, packet[0]} | 279 return UnexpectedMessageError{msgNewKeys, packet[0]} |
283 } | |
284 if err = s.transport.reader.setupKeys(clientKeys, result.K, result.H, s.
sessionId, kex.Hash()); err != nil { | |
285 return | |
286 } | 280 } |
287 | 281 |
288 return | 282 return |
289 } | 283 } |
290 | 284 |
291 func isAcceptableAlgo(algo string) bool { | 285 func isAcceptableAlgo(algo string) bool { |
292 switch algo { | 286 switch algo { |
293 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC
DSA521, | 287 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoEC
DSA521, |
294 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD
SA384v01, CertAlgoECDSA521v01: | 288 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECD
SA384v01, CertAlgoECDSA521v01: |
295 return true | 289 return true |
(...skipping 21 matching lines...) Expand all Loading... |
317 pubKey: make([]byte, len(pubKey)), | 311 pubKey: make([]byte, len(pubKey)), |
318 result: result, | 312 result: result, |
319 } | 313 } |
320 copy(c.pubKey, pubKey) | 314 copy(c.pubKey, pubKey) |
321 s.cachedPubKeys = append(s.cachedPubKeys, c) | 315 s.cachedPubKeys = append(s.cachedPubKeys, c) |
322 } | 316 } |
323 | 317 |
324 return result | 318 return result |
325 } | 319 } |
326 | 320 |
327 func (s *ServerConn) authenticate(H []byte) error { | 321 func (s *ServerConn) authenticate() error { |
328 var userAuthReq userAuthRequestMsg | 322 var userAuthReq userAuthRequestMsg |
329 var err error | 323 var err error |
330 var packet []byte | 324 var packet []byte |
331 | 325 |
332 userAuthLoop: | 326 userAuthLoop: |
333 for { | 327 for { |
334 » » if packet, err = s.readPacket(); err != nil { | 328 » » if packet, err = s.transport.readPacket(); err != nil { |
335 return err | 329 return err |
336 } | 330 } |
337 if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); er
r != nil { | 331 if err = unmarshal(&userAuthReq, packet, msgUserAuthRequest); er
r != nil { |
338 return err | 332 return err |
339 } | 333 } |
340 | 334 |
341 if userAuthReq.Service != serviceSSH { | 335 if userAuthReq.Service != serviceSSH { |
342 return errors.New("ssh: client attempted to negotiate fo
r unknown service: " + userAuthReq.Service) | 336 return errors.New("ssh: client attempted to negotiate fo
r unknown service: " + userAuthReq.Service) |
343 } | 337 } |
344 | 338 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 return ParseError{msgUserAuthRequest} | 383 return ParseError{msgUserAuthRequest} |
390 } | 384 } |
391 algo := string(algoBytes) | 385 algo := string(algoBytes) |
392 | 386 |
393 pubKey, payload, ok := parseString(payload) | 387 pubKey, payload, ok := parseString(payload) |
394 if !ok { | 388 if !ok { |
395 return ParseError{msgUserAuthRequest} | 389 return ParseError{msgUserAuthRequest} |
396 } | 390 } |
397 if isQuery { | 391 if isQuery { |
398 // The client can query if the given public key | 392 // The client can query if the given public key |
399 » » » » // would be ok. | 393 » » » » // would be okay. |
400 if len(payload) > 0 { | 394 if len(payload) > 0 { |
401 return ParseError{msgUserAuthRequest} | 395 return ParseError{msgUserAuthRequest} |
402 } | 396 } |
403 if s.testPubKey(userAuthReq.User, algo, pubKey)
{ | 397 if s.testPubKey(userAuthReq.User, algo, pubKey)
{ |
404 okMsg := userAuthPubKeyOkMsg{ | 398 okMsg := userAuthPubKeyOkMsg{ |
405 Algo: algo, | 399 Algo: algo, |
406 PubKey: string(pubKey), | 400 PubKey: string(pubKey), |
407 } | 401 } |
408 » » » » » if err = s.writePacket(marshal(msgUserAu
thPubKeyOk, okMsg)); err != nil { | 402 » » » » » if err = s.transport.writePacket(marshal
(msgUserAuthPubKeyOk, okMsg)); err != nil { |
409 return err | 403 return err |
410 } | 404 } |
411 continue userAuthLoop | 405 continue userAuthLoop |
412 } | 406 } |
413 } else { | 407 } else { |
414 sig, payload, ok := parseSignature(payload) | 408 sig, payload, ok := parseSignature(payload) |
415 if !ok || len(payload) > 0 { | 409 if !ok || len(payload) > 0 { |
416 return ParseError{msgUserAuthRequest} | 410 return ParseError{msgUserAuthRequest} |
417 } | 411 } |
418 // Ensure the public key algo and signature algo | 412 // Ensure the public key algo and signature algo |
419 // are supported. Compare the private key | 413 // are supported. Compare the private key |
420 // algorithm name that corresponds to algo with | 414 // algorithm name that corresponds to algo with |
421 // sig.Format. This is usually the same, but | 415 // sig.Format. This is usually the same, but |
422 // for certs, the names differ. | 416 // for certs, the names differ. |
423 if !isAcceptableAlgo(algo) || !isAcceptableAlgo(
sig.Format) || pubAlgoToPrivAlgo(algo) != sig.Format { | 417 if !isAcceptableAlgo(algo) || !isAcceptableAlgo(
sig.Format) || pubAlgoToPrivAlgo(algo) != sig.Format { |
424 break | 418 break |
425 } | 419 } |
426 » » » » signedData := buildDataSignedForAuth(H, userAuth
Req, algoBytes, pubKey) | 420 » » » » signedData := buildDataSignedForAuth(s.transport
.sessionID, userAuthReq, algoBytes, pubKey) |
427 » » » » key, _, ok := parsePubKey(pubKey) | 421 » » » » key, _, ok := ParsePublicKey(pubKey) |
428 if !ok { | 422 if !ok { |
429 return ParseError{msgUserAuthRequest} | 423 return ParseError{msgUserAuthRequest} |
430 } | 424 } |
431 | 425 |
432 if !key.Verify(signedData, sig.Blob) { | 426 if !key.Verify(signedData, sig.Blob) { |
433 return ParseError{msgUserAuthRequest} | 427 return ParseError{msgUserAuthRequest} |
434 } | 428 } |
435 // TODO(jmpittman): Implement full validation fo
r certificates. | 429 // TODO(jmpittman): Implement full validation fo
r certificates. |
436 s.User = userAuthReq.User | 430 s.User = userAuthReq.User |
437 if s.testPubKey(userAuthReq.User, algo, pubKey)
{ | 431 if s.testPubKey(userAuthReq.User, algo, pubKey)
{ |
(...skipping 10 matching lines...) Expand all Loading... |
448 failureMsg.Methods = append(failureMsg.Methods, "publick
ey") | 442 failureMsg.Methods = append(failureMsg.Methods, "publick
ey") |
449 } | 443 } |
450 if s.config.KeyboardInteractiveCallback != nil { | 444 if s.config.KeyboardInteractiveCallback != nil { |
451 failureMsg.Methods = append(failureMsg.Methods, "keyboar
d-interactive") | 445 failureMsg.Methods = append(failureMsg.Methods, "keyboar
d-interactive") |
452 } | 446 } |
453 | 447 |
454 if len(failureMsg.Methods) == 0 { | 448 if len(failureMsg.Methods) == 0 { |
455 return errors.New("ssh: no authentication methods config
ured but NoClientAuth is also false") | 449 return errors.New("ssh: no authentication methods config
ured but NoClientAuth is also false") |
456 } | 450 } |
457 | 451 |
458 » » if err = s.writePacket(marshal(msgUserAuthFailure, failureMsg));
err != nil { | 452 » » if err = s.transport.writePacket(marshal(msgUserAuthFailure, fai
lureMsg)); err != nil { |
459 return err | 453 return err |
460 } | 454 } |
461 } | 455 } |
462 | 456 |
463 packet = []byte{msgUserAuthSuccess} | 457 packet = []byte{msgUserAuthSuccess} |
464 » if err = s.writePacket(packet); err != nil { | 458 » if err = s.transport.writePacket(packet); err != nil { |
465 return err | 459 return err |
466 } | 460 } |
467 | 461 |
468 return nil | 462 return nil |
469 } | 463 } |
470 | 464 |
471 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by | 465 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by |
472 // asking the client on the other side of a ServerConn. | 466 // asking the client on the other side of a ServerConn. |
473 type sshClientKeyboardInteractive struct { | 467 type sshClientKeyboardInteractive struct { |
474 *ServerConn | 468 *ServerConn |
475 } | 469 } |
476 | 470 |
477 func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest
ions []string, echos []bool) (answers []string, err error) { | 471 func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, quest
ions []string, echos []bool) (answers []string, err error) { |
478 if len(questions) != len(echos) { | 472 if len(questions) != len(echos) { |
479 return nil, errors.New("ssh: echos and questions must have equal
length") | 473 return nil, errors.New("ssh: echos and questions must have equal
length") |
480 } | 474 } |
481 | 475 |
482 var prompts []byte | 476 var prompts []byte |
483 for i := range questions { | 477 for i := range questions { |
484 prompts = appendString(prompts, questions[i]) | 478 prompts = appendString(prompts, questions[i]) |
485 prompts = appendBool(prompts, echos[i]) | 479 prompts = appendBool(prompts, echos[i]) |
486 } | 480 } |
487 | 481 |
488 » if err := c.writePacket(marshal(msgUserAuthInfoRequest, userAuthInfoRequ
estMsg{ | 482 » if err := c.transport.writePacket(marshal(msgUserAuthInfoRequest, userAu
thInfoRequestMsg{ |
489 Instruction: instruction, | 483 Instruction: instruction, |
490 NumPrompts: uint32(len(questions)), | 484 NumPrompts: uint32(len(questions)), |
491 Prompts: prompts, | 485 Prompts: prompts, |
492 })); err != nil { | 486 })); err != nil { |
493 return nil, err | 487 return nil, err |
494 } | 488 } |
495 | 489 |
496 » packet, err := c.readPacket() | 490 » packet, err := c.transport.readPacket() |
497 if err != nil { | 491 if err != nil { |
498 return nil, err | 492 return nil, err |
499 } | 493 } |
500 if packet[0] != msgUserAuthInfoResponse { | 494 if packet[0] != msgUserAuthInfoResponse { |
501 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack
et[0]} | 495 return nil, UnexpectedMessageError{msgUserAuthInfoResponse, pack
et[0]} |
502 } | 496 } |
503 packet = packet[1:] | 497 packet = packet[1:] |
504 | 498 |
505 n, packet, ok := parseUint32(packet) | 499 n, packet, ok := parseUint32(packet) |
506 if !ok || int(n) != len(questions) { | 500 if !ok || int(n) != len(questions) { |
(...skipping 14 matching lines...) Expand all Loading... |
521 } | 515 } |
522 | 516 |
523 return answers, nil | 517 return answers, nil |
524 } | 518 } |
525 | 519 |
526 const defaultWindowSize = 32768 | 520 const defaultWindowSize = 32768 |
527 | 521 |
528 // Accept reads and processes messages on a ServerConn. It must be called | 522 // Accept reads and processes messages on a ServerConn. It must be called |
529 // in order to demultiplex messages to any resulting Channels. | 523 // in order to demultiplex messages to any resulting Channels. |
530 func (s *ServerConn) Accept() (Channel, error) { | 524 func (s *ServerConn) Accept() (Channel, error) { |
531 » return s.mux.Accept() | 525 » in, ok := <-s.mux.incomingChannels |
| 526 » if !ok { |
| 527 » » return nil, io.EOF |
| 528 » } |
| 529 » return newCompatChannel(in), nil |
532 } | 530 } |
533 | 531 |
534 // A Listener implements a network listener (net.Listener) for SSH connections. | 532 // A Listener implements a network listener (net.Listener) for SSH connections. |
535 type Listener struct { | 533 type Listener struct { |
536 listener net.Listener | 534 listener net.Listener |
537 config *ServerConfig | 535 config *ServerConfig |
538 } | 536 } |
539 | 537 |
540 // Addr returns the listener's network address. | 538 // Addr returns the listener's network address. |
541 func (l *Listener) Addr() net.Addr { | 539 func (l *Listener) Addr() net.Addr { |
(...skipping 21 matching lines...) Expand all Loading... |
563 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { | 561 func Listen(network, addr string, config *ServerConfig) (*Listener, error) { |
564 l, err := net.Listen(network, addr) | 562 l, err := net.Listen(network, addr) |
565 if err != nil { | 563 if err != nil { |
566 return nil, err | 564 return nil, err |
567 } | 565 } |
568 return &Listener{ | 566 return &Listener{ |
569 l, | 567 l, |
570 config, | 568 config, |
571 }, nil | 569 }, nil |
572 } | 570 } |
LEFT | RIGHT |